Code前端首页关于Code前端联系我们

方式1,平滑重启

terry 5小时前 阅读数 8 #Vue

做Vue单页应用开发的同学,肯定遇到过这种情况:本地跑项目时,路由跳转、刷新页面都顺顺当当,一部署到Nginx服务器,刷新页面就突然跳出404错误,明明代码没改,咋部署后就出问题了?这得从Vue Router的工作逻辑和Nginx的请求处理方式说起,今天咱们一步步拆解原因和解决办法。

Vue Router两种路由模式,为啥history模式容易触发404?

先得明白Vue Router有两种路由模式:哈希模式(hash mode)历史模式(history mode),这俩模式的区别,直接决定了部署后会不会出现404。

哈希模式下,URL长这样:https://xxx.com/#/about,这里的是锚点标识符,浏览器发请求时,只会把前面的部分(也就是https://xxx.com)发给服务器,后面的内容是前端自己处理的路由,所以不管刷新哪个哈希路由,服务器只需要返回根路径的index.html,前端再解析后面的内容渲染页面,自然不会有404。

但历史模式更“好看”,URL变成https://xxx.com/about这种无的形式,这时候问题就来了:刷新页面时,浏览器会把整个https://xxx.com/about当作请求路径发给服务器,Nginx作为服务器,默认会去自己配置的静态资源目录里,找有没有叫about的文件或者about文件夹里的index文件,可Vue单页应用的路由是前端JS控制的,服务器里根本没有about这个物理文件,Nginx找不到资源,就返回404了。

Nginx处理请求的逻辑,为啥默认“不认识”前端路由?

Nginx本质是静态资源服务器,它处理请求的逻辑很直接:收到请求后,根据配置的root(或alias)目录,去对应路径下找文件,比如你配置root /usr/share/nginx/html,请求/about时,Nginx会去/usr/share/nginx/html里找about文件;如果是目录请求(比如/about/),就找about文件夹里的index文件。

但Vue单页应用是“单页”,所有路由逻辑都在index.html里由JS处理,也就是说,不管用户访问/about还是/user,服务器都应该返回index.html,让前端路由接管后续操作,但Nginx默认没这个“觉悟”,它只认物理文件,所以才会出现刷新404的情况。

三步走,解决Nginx下Vue Router history模式404问题

知道了原因,解决起来就有方向了:让Nginx把找不到的请求,统统导向index.html,具体分三步操作。

步骤1:确认Vue项目的路由模式配置

先打开Vue项目里的路由配置文件(一般是src/router/index.js),看是不是用了history模式:

const router = new VueRouter({
  mode: 'history', // 这里如果是history模式,才需要Nginx特殊配置
  base: process.env.BASE_URL,
  routes: [...]
})

如果是hash模式(默认就是hash,除非你主动改成history),理论上不会有404问题;要是确实用了history模式,就继续往下走。

步骤2:修改Nginx的server配置块

找到Nginx的配置文件(常见路径是/etc/nginx/conf.d/下的站点配置,或者/etc/nginx/nginx.conf里的server块),重点修改location / {}部分,加入try_files指令:

server {
  listen 80; # 或443(https)
  server_name 你的域名或服务器IP;
  root /usr/share/nginx/html; # Vue项目打包后dist目录的绝对路径
  location / {
    try_files $uri $uri/ /index.html; # 核心配置!
    # 下面是可选的性能优化配置(如gzip、缓存)
    gzip on;
    gzip_types text/plain application/javascript text/css;
  }
  # 可选:单独处理静态资源,避免被try_files拦截
  location /static/ {
    expires 30d; # 静态资源缓存30天
    autoindex off; # 关闭目录浏览
  }
}

解释下try_files $uri $uri/ /index.html;:Nginx会按顺序检查这三个“候选”:

  • $uri:请求的资源文件(比如访问/about,就找about文件);
  • $uri/:请求的目录(比如访问/about,就找about文件夹里的index文件);
  • 前两个都找不到,就跳转到/index.html,把请求交给前端路由处理。

步骤3:重启Nginx并验证

配置改完后,执行命令重启Nginx(不同系统命令可能不同):

# 方式2:系统服务重启(CentOS/Ubuntu等)
systemctl reload nginx  

重启后,打开页面测试:刷新不同路由(比如/about/user),看是否还出现404,如果页面正常加载,说明配置生效;要是还报错,优先检查这几点:

  • root路径是否正确?比如Vue打包后的dist文件夹,是否真的传到了/usr/share/nginx/html
  • server_name是否和你访问的域名/IP一致?比如配置的是www.xxx.com,但你用168.1.1访问,就会匹配不到;
  • 有没有其他location规则干扰?比如之前配置过其他路径的反向代理,导致请求被拦截。

特殊场景:项目部署在子路径下,咋处理?

有些同学的项目不是部署在域名根路径(比如https://xxx.com/),而是子路径(比如https://xxx.com/my-app/),这时候配置更复杂,得同时调整Vue和Nginx的配置。

第一步:Vue项目里配置base属性

如果是Vue CLI创建的项目,在vue.config.js里设置publicPath;如果是直接配置Vue Router,设置base属性:

// vue.config.js(Vue CLI项目)
module.exports = {
  publicPath: '/my-app/' // 部署的子路径
}
// 或者router/index.js(直接配置Vue Router)
const router = new VueRouter({
  mode: 'history',
  base: '/my-app/', // 和部署子路径一致
  routes: [...]
})

第二步:Nginx配置子路径的location

修改Nginx的server块,针对子路径配置location,还要注意rootalias的区别:

server {
  ...
  location /my-app/ {
    alias /usr/share/nginx/html/my-app/; # 用alias替换整个路径
    try_files $uri $uri/ /my-app/index.html; # 回退到子路径下的index.html
  }
}

这里解释下aliasroot的区别:

  • root是“拼接路径”:比如root /usr/share/nginx/html,请求/my-app/js/app.js会变成/usr/share/nginx/html/my-app/js/app.js
  • alias是“替换路径”:alias /usr/share/nginx/html/my-app/,请求/my-app/js/app.js会直接指向/usr/share/nginx/html/my-app/js/app.js

如果用root,得写成:

location ^~ /my-app/ { # ^~表示优先匹配该location
  root /usr/share/nginx/html;
  try_files $uri $uri/ /my-app/index.html;
}

两种方式都能实现,但要保证路径对应上,否则静态资源会404。

哈希模式下还遇到404?排查这几点

如果你的项目用的是哈希模式(URL带),理论上刷新不会触发404(因为浏览器只请求前面的根路径),要是还遇到404,大概率是这几个原因:

  1. 部署路径错误:Nginx的root没指向Vue打包后的dist目录,导致根路径下没有index.html,比如你把dist传到了/usr/share/nginx/html/my-app,但root配成了/usr/share/nginx/html,就会找不到文件。

  2. 服务器缓存干扰:之前配置过history模式,Nginx缓存了旧配置,导致请求被错误处理,这时候重启Nginx(甚至重启服务器),或者清除浏览器缓存再试。

  3. 域名/端口不匹配:Nginx配置的server_namewww.xxx.com,但你用168.1.1或者其他域名访问,请求会匹配到其他server块,导致404。

核心是让Nginx把前端路由请求“导回”index.html

Vue Router的history模式让URL更简洁,但需要服务器配合——因为刷新时浏览器会真实请求URL路径,而Nginx默认只认物理文件,解决思路很清晰:用try_files指令,把所有找不到的请求都导向index.html,让前端路由接管。

记住这几个关键步骤:确认路由模式是history、修改Nginx配置加入try_files、处理子路径部署的特殊情况,把这些细节做好,刷新页面404的问题基本就能解决,要是还碰到奇怪的问题,随时留言,咱们一起排查~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门