或 sudo service nginx reload
p>做Vue项目时,只要用了路由的history模式,部署到服务器后大概率会碰到「直接访问子路由404」的问题,比如你做了个/about
页面,本地开发好好的,部署到Nginx后直接输域名/about
,页面就崩了,这时候就得靠Nginx配置来解决!这篇文章从「为啥要配」「咋配」「踩坑咋修」三个角度,把Vue - Router history模式的Nginx配置讲透,新手也能跟着操作~
Vue - Router的history和hash模式,到底差在哪?
先看hash模式:网址里有个号,比如http://xxx.com/#/home
,这个叫哈希符,它后面的内容是「前端路由」,浏览器不会把后面的部分发给服务器,所以不管你怎么跳路由,服务器只需要返回index.html
,剩下的路由逻辑前端自己处理,部署时基本不用操心服务器配置。
再看history模式:它用HTML5的History API(比如pushState
、replaceState
)来管理路由,网址变成http://xxx.com/home
这种“干净”的样子,但问题也来了:当用户直接在浏览器输入http://xxx.com/home
,或者刷新页面时,浏览器会把整个网址发给服务器请求资源,可服务器里根本没有home
这个「物理文件」啊(因为单页应用只有index.html
是入口),这时候服务器就会返回404——所以必须让Nginx把这种请求“导”到index.html
,让前端路由自己处理。
为啥history模式必须配Nginx?本质是「前端路由」和「服务器请求」的矛盾
单页应用(SPA)的逻辑是:所有页面切换都是前端用JS控制的,服务器只需要返回一个index.html
,里面的JS再根据路由渲染不同组件,但history模式下,用户访问的网址是「真实路径」(比如/home
),这时候服务器收到请求,会以为要找/home
这个文件或目录。
可实际项目里,只有index.html
是真实存在的静态文件,其他路由都是前端“虚拟”的,所以Nginx必须拦截这些「不存在的资源请求」,把它们转发到index.html
,让前端路由接管,要是不配,直接访问子路由就会404,页面白屏。
Nginx配置history模式的核心逻辑:「静态资源直接返回,页面请求指向index.html」
Nginx配置要分两步走:
- 静态资源优先返回:CSS、JS、图片这些静态文件,得让Nginx能找到并直接返回,保证页面样式、交互正常加载;
- 页面请求统一转发:除了静态资源,其他所有请求(比如用户直接访问
/about
)都导向index.html
,让前端路由解析路径、渲染对应组件。
手把手配Nginx!从基础到复杂场景
下面分“部署在域名根路径”和“部署在子路径”两种场景,一步步讲配置方法。
场景1:项目部署在域名根路径(如xxx.com
)
假设你的Vue项目打包后,dist
文件夹传到了服务器的/var/www/my - vue - app
目录下,配置Nginx的server
块如下:
server { listen 80; # 监听80端口(HTTP) server_name xxx.com; # 你的域名或服务器IP root /var/www/my - vue - app; # 项目根目录(dist所在路径) index index.html; # 默认首页 # 处理静态资源:匹配JS、CSS、图片等文件 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 30d; # 静态资源缓存30天,加速重复访问 access_log off; # 关闭访问日志,减少服务器开销 } # 处理页面请求:非静态资源的请求,都导向index.html location / { try_files $uri $uri/ /index.html; } }
解释try_files
:它会按顺序检查三个东西——
$uri
:当前请求的文件(比如用户访问/about
,就检查服务器是否有about
这个文件);$uri/
:当前请求对应的目录(比如检查是否有about/
这个目录);- 前两个都不存在,就跳转到
/index.html
,让前端路由接管。
场景2:项目部署在子路径(如xxx.com/my - app
)
如果项目要部署在域名的子路径下(比如xxx.com/my - app
),配置更要小心,需同时调整Vue - Router的base
属性和Nginx的路径匹配。
步骤1:修改Vue - Router的base
在router/index.js
里,给createRouter
配置base
属性,值为子路径(带斜杠):
const router = createRouter({ history: createWebHistory('/my - app/'), // history模式 + 子路径 routes, });
步骤2:修改Nginx配置
Nginx的server
块要针对子路径做匹配,且注意root
和alias
的区别(后面讲坑点时会详细说):
server { listen 80; server_name xxx.com; # 匹配子路径/my - app/的请求 location /my - app/ { alias /var/www/my - vue - app/; # 项目dist所在目录(注意结尾的/) index index.html; # 处理静态资源:单独匹配子路径下的静态文件 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { alias /var/www/my - vue - app/; # 静态资源的实际路径 expires 30d; access_log off; } # 处理页面请求:跳转到子路径下的index.html try_files $uri $uri/ /my - app/index.html; } }
关键细节:部署子路径时,用alias
比root
更安全,因为root
是“路径拼接”(比如location /my - app
+ root /var/www
,实际路径是/var/www/my - app
),而alias
是“路径替换”(location /my - app/
直接对应/var/www/my - vue - app/
),能避免路径重复导致的404。
配完还404?这些坑90%的人都踩过
配置后还是报错?别慌,先排查这几个高频坑:
坑1:静态资源路径配置错误
Vue项目打包时,publicPath
要和子路径/history模式匹配,比如部署在/my - app
下,需在vue.config.js
里配置:
module.exports = { publicPath: '/my - app/', // 和router的base保持一致 };
否则打包后,JS、CSS的路径会是/xxx.js
(实际需要/my - app/xxx.js
),导致静态资源404。
坑2:Nginx的root
和alias
用混了
部署子路径时,若错误使用root
,会导致路径重复。
location /my - app { root /var/www/my - vue - app; # 错误!实际路径会变成/var/www/my - vue - app/my - app ... }
改成alias
就能解决:alias /var/www/my - vue - app/;
坑3:Nginx配置没生效
改了配置文件后,必须重启或重载Nginx才会生效,Linux下执行:
sudo systemctl reload nginx # CentOS/Ubuntu通用``` 如果还不生效,用`nginx - t`检查配置文件语法,有错误会直接提示哪里错了。 #### 坑4:Vue - Router的`mode`没改成`history` 别光顾着改Nginx,代码里的路由模式也要改!在`router/index.js`中,确保: ```js import { createWebHistory, createRouter } from 'vue - router'; const router = createRouter({ history: createWebHistory(), // 或带base的createWebHistory('/my - app/') routes, });
默认是hash
模式(createWebHashHistory
),若没改,就算Nginx配置对了,路由还是带,且直接访问子路径会报错。
生产环境进阶:性能和安全优化
配置能跑通只是基础,生产环境还要考虑加载速度和安全性,这几个优化点值得加:
优化1:开启Gzip压缩静态资源
让JS、CSS体积更小,加载更快,在Nginx配置里加:
gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; gzip_min_length 1024; # 小于1k的文件不压缩(太小的文件压缩意义不大)
优化2:精细化缓存策略
- 静态资源(JS、CSS、图片)设长缓存(比如
expires 30d;
),减少重复请求; index.html
不能缓存(否则用户看不到最新页面),单独配置:location = /index.html { add_header Cache - Control "no - cache, no - store, must - revalidate"; add_header Pragma no - cache; add_header Expires 0; }
优化3:强制HTTPS + SSL证书
现在网站基本要求HTTPS,需配置SSL证书,并把HTTP请求301重定向到HTTPS:
# HTTP -> HTTPS 重定向 server { listen 80; server_name xxx.com; return 301 https://$server_name$request_uri; } # HTTPS 配置 server { listen 443 ssl; server_name xxx.com; ssl_certificate /path/to/cert.pem; # 证书路径 ssl_certificate_key /path/to/key.pem; # 私钥路径 # 其他配置(如静态资源、try_files等)... }
优化4:多服务器负载均衡下的一致性
如果项目用了负载均衡(多台Nginx反向代理),要确保所有服务器的Nginx配置完全一致,且前端路由的base
、静态资源路径在所有节点都能正确解析,必要时用Session共享或配置中心,避免不同节点返回结果不一致。
Vue - Router history模式的Nginx配置,核心是「让服务器把页面请求导到index.html,同时正确返回静态资源」,只要理解了前后端路由的分工,再跟着步骤配,避开root/alias混淆、静态资源路径这些坑,部署后的单页应用就能稳得一批~要是还有问题,评论区留言,我帮你分析场景!
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。