详解 Vue SPA 路由:# 锚点与 Nginx try_files 解决刷新 404 问题
- 内容
- 评论
- 相关
在 Vue 单页应用(SPA)开发中,路由跳转后刷新页面出现 404 是高频问题。这一现象的核心矛盾,在于前端路由模式与服务器请求逻辑的不匹配 —— 带
# 的哈希模式无需额外配置即可避免刷新报错,而美观的历史模式则需要通过 Nginx 的 try_files 指令兜底。本文将从原理到实践,彻底讲清两者的逻辑与用法。
一、先搞懂:URL 中 # 的特殊作用
Vue 路由默认使用哈希模式(hash mode),其 URL 会带有
# 符号(如 http://xxx.com/#/article/240)。这个看似普通的符号,是解决刷新报错的 “天然屏障”,核心源于其在 URL 中的本质定义:
1. # 是 “片段标识符”,而非服务器请求路径
# 在 URL 中被称为「片段标识符(Fragment Identifier)」,原本用于定位页面内锚点(如 <a href="#section1"> 跳转到页面指定章节)。它有一个关键特性:浏览器不会将 # 及其后面的内容发送给服务器。
简单说,当你刷新
http://xxx.com/#/article/240 时,浏览器实际向服务器发送的请求路径只有 http://xxx.com/,#/article/240 这部分会被浏览器保留在本地,仅用于前端逻辑处理。
2. 哈希模式刷新不报错的完整流程
-
路由跳转时:Vue Router 监听
#后面的路径变化(如从#/home到#/article/240),通过前端 JS 切换组件,不发起新的服务器请求(这也是 SPA “无刷新跳转” 的核心)。 -
页面刷新时:
-
服务器仅收到根路径
/的请求,按默认静态文件规则返回 Vue 入口文件index.html(无需额外配置)。 -
index.html加载后,Vue 会读取 URL 中#后面的路径(/article/240),通过前端路由匹配对应的组件,页面正常显示。
-
服务器仅收到根路径
3. 哈希模式的优缺点
- 优点:无需配置服务器,部署简单,刷新永远不会 404。
-
缺点:URL 中带有
#,美观度不足;部分场景(如微信分享、SEO 优化)可能受影响。
二、历史模式:去掉 # 后,为何刷新就 404?
为了获得更简洁的 URL(如
http://xxx.com/article/240),很多开发者会将 Vue 路由切换为历史模式(history mode),只需在路由配置中添加 mode: 'history':
javascript
运行
const router = new VueRouter({ mode: 'history', // 开启历史模式,去掉 URL 中的 # routes: [...] })
但切换后会出现新问题:路由跳转正常,刷新页面直接 404。这背后的逻辑与哈希模式完全不同:
1. 历史模式的核心矛盾
历史模式去掉了
#,URL 与传统多页应用的路径格式一致。此时刷新页面时,浏览器会将整个 URL 路径(如 /article/240)作为请求路径发送给服务器。
而服务器的默认逻辑是:根据请求路径查找对应的文件或目录。由于 Vue 是单页应用,服务器根目录下根本没有
article/240 这个文件或文件夹,因此会返回 404 错误。
2. 对比:两种模式的刷新请求差异
| 路由模式 | 示例 URL | 刷新时服务器收到的请求路径 | 服务器处理结果 |
|---|---|---|---|
| 哈希模式 |
http://xxx.com/#/article/240
|
/(仅根路径)
|
返回 index.html,页面正常
|
| 历史模式 |
http://xxx.com/article/240
|
/article/240(完整路径)
|
找不到对应文件,返回 404 |
三、Nginx try_files:解决历史模式刷新 404 的关键
要让历史模式既保留美观 URL,又能正常刷新,核心是让服务器 “找不到对应文件时,兜底返回 Vue 入口
index.html”。而 Nginx 的 try_files 指令,正是实现这一逻辑的核心工具。
1. try_files 指令的核心作用
try_files 是 Nginx 的内置指令,作用是按顺序检查请求路径对应的文件 / 目录是否存在,找到第一个存在的资源就返回;若所有路径都不存在,则执行最后一个兜底选项。
其语法格式为:
nginx
try_files $uri $uri/ /index.html;
逐段拆解每个参数的含义:
(1)第一个参数:$uri —— 优先匹配真实文件
$uri 是 Nginx 内置变量,代表当前请求的路径(不含查询参数)。例如:
-
请求
http://xxx.com/css/app.css,$uri为/css/app.css,Nginx 会去项目根目录查找该文件,存在则直接返回(保证静态资源正常加载)。 -
请求
http://xxx.com/article/240,$uri为/article/240,根目录下无该文件,进入下一个匹配。
(2)第二个参数:$uri/ —— 再匹配真实目录
$uri/ 表示在 $uri 后添加 /,即检查是否存在对应的目录。例如:
-
请求
http://xxx.com/article/240,$uri/为/article/240/,根目录下无该目录,进入最后一个兜底选项。
(3)第三个参数:/index.html —— 兜底返回 Vue 入口
当前面的文件、目录都找不到时,Nginx 会直接返回根目录下的
index.html。此时:
-
浏览器加载
index.html后,Vue 会启动并读取 URL 中的路径(/article/240)。 - Vue Router 匹配对应的路由组件,页面正常显示,完美解决刷新 404 问题。
2. 历史模式的完整 Nginx 配置示例
结合
try_files,历史模式的 Nginx 完整配置如下(可直接复制使用):
nginx
server { listen 80; # 监听端口 server_name ruoyiblog.wlphp.com; # 你的域名 root /usr/share/nginx/html/ruoyiblog; # Vue 项目打包后的 dist 目录路径 # 核心配置:解决历史模式刷新 404 location / { try_files $uri $uri/ /index.html; # 按顺序匹配,兜底返回 index.html index index.html index.htm; # 默认首页 } # 可选:配置静态资源缓存(优化性能) location ~* \.(css|js|png|jpg|jpeg|gif|ico)$ { expires 7d; # 静态资源缓存 7 天 add_header Cache-Control "public, max-age=604800"; } }
配置后执行
nginx -s reload 重启 Nginx,历史模式刷新即可正常显示。
3. 关键注意点
-
根目录配置:
root必须指向 Vue 项目打包后的dist目录,否则 Nginx 无法找到index.html和静态资源。 -
子目录部署:若项目部署在子目录(如
http://xxx.com/blog/article/240),需在 Vue 路由中设置base: '/blog/',同时 Nginx 的location需改为location /blog/,确保路径匹配正确。 -
静态资源兼容:
try_files会优先匹配真实文件(如css、js、img),因此静态资源不会被转发,可正常加载。
四、总结:两种模式的选择与配置建议
- 若追求简单部署,无需美观 URL:直接使用默认的哈希模式,无需配置服务器,刷新永远不会 404。
-
若需要无
#的美观 URL:切换为历史模式,并通过 Nginx 的try_files指令配置兜底转发,核心是try_files $uri $uri/ /index.html;。
本质上,
# 是通过 “隔离前端路由与服务器请求” 避免 404,而 try_files 是通过 “服务器兜底转发” 解决历史模式的路径匹配问题。两种方案各有优劣,可根据项目需求灵活选择。