如何正确配置Docker容器化Web应用的CSS引入路径?
Docker容器中CSS资源404因构建路径与容器内结构不匹配。需调整Vite/Webpack的base/publicPath为绝对前缀,并配置Nginx的location+root规则,使前端构建、容器文件与Nginx路径对齐,即可解决。
为什么CSS里的url(../fonts/icon.woff)在Docker容器里总404
别急着甩锅给Nginx配置,先看看构建时CSS里写的那条相对路径,跟容器内真实的文件结构是不是“两家人”。大概率是路径没对上。举个例子:Vite默认打包出dist/css/app.css,里面写着url(../fonts/icon.woff)。浏览器看到这个,就会乖乖去请求/fonts/icon.woff。但你用COPY dist/ /usr/share/nginx/html/把整个dist丢进容器后,字体文件实际上躺在/usr/share/nginx/html/fonts/icon.woff。看明白了吧?Nginx根目录下压根没有/fonts/这个路径——能不404吗?
验证方法很直接:docker exec -it 。如果满屏都是../,说明问题出在构建阶段,根本不必去折腾Nginx。有几个小技巧帮你快速定位:
- 别光看页面样式是否正常——打开浏览器Network面板,筛选Font,点开那个404请求,看看Request URL是不是你脑子里预期的那条路径。
ls -R /usr/share/nginx/html/ | head -20确认一下fonts/和css/是不是同级的。如果它们在不同目录下,那路径肯定对不上。- 本地用
file://协议双击HTML会失效,因为/fonts/会被解析成磁盘根目录——这不是容器的问题,是协议限制,别把它当罪魁祸首。
Vite或Webpack必须设base/publicPath为绝对前缀
相对路径就是个坑。所有资源URL必须在构建阶段就带上明确的绝对前缀,而且这个前缀必须和Nginx规则完全对齐。如果设成./或空字符串,进容器照样404,百试百灵。
- Vite用户:在
vite.config.ts里写base: '/static/'。这样url('@/assets/logo.png')打包之后会变成/static/assets/logo.xxxx.png,一切路径都稳稳的。 - Webpack/Vue CLI用户:在
vue.config.js里设publicPath: '/static/'。保证index.html中的link标签以及CSS里所有url()都带着/static/前缀。 - 千万别用
publicPath: './'——那东西生成的还是相对路径。一旦子路径部署(比如/my-app/),路径就错位了,怎么调都调不对。
Nginx的location必须用root而非alias匹配/static/
alias很容易少一层路径,而root更直观、更可靠。假设你把整个dist/拷到了/usr/share/nginx/html/,那么/static/就应该指向这个目录下的static/子目录。
- 正确写法:
location ^~ /static/ { root /usr/share/nginx/html; }→ 请求/static/css/app.css会映射到/usr/share/nginx/html/static/css/app.css,严丝合缝。 - 错误写法:
location /static/ { alias /usr/share/nginx/html/static/; }→ 请求/static/css/app.css会跑去找/usr/share/nginx/html/css/app.css(注意,static/被截掉了,路径直接少了一层)。 - 如果用了
include /etc/nginx/conf.d/*.conf,建议把静态资源的配置文件命名为00-static.conf,确保它比location / { }先加载,避免规则优先级打架。
验证路径是否真正打通的三步检查法
别只刷页面,那容易骗人。要逐层检查前端、容器、Nginx三端是否一致。
- 查构建产物:
grep -r "/static/" dist/。确认CSS、JS、HTML里所有资源URL都带上/static/,一个都不漏。 - 进容器看物理结构:
docker exec -it。确认文件真的存在,别是构建时忘了复制。ls -l /usr/share/nginx/html/static/fonts/ - 看Nginx日志:
docker logs。如果有输出,说明请求已经发到了Nginx,但文件没找到——问题出在路径映射上。| grep "GET /static/.* 404"
最容易被忽略的细节是:前端base和Nginxlocation的值不一致。比如一个设/assets/,另一个配/static/,中间差了一层。这种低级的“门牌号对不上”,怎么折腾都是404。
