在部署 Vue.js 单页面应用(SPA)时,遇到刷新页面时返回 404 错误是一个常见问题。这个问题通常是由于服务器不知道如何处理 SPA 的路由而导致的。
原因
在 Vue.js SPA 中,前端路由由 Vue Router 处理。当你在应用中导航时,Vue Router 可以处理这些路由并加载相应的组件。但是,当你直接刷新浏览器或访问一个特定的 URL 时,浏览器会向服务器发出请求,而服务器可能不知道如何处理这些客户端路由,导致返回 404 错误。
先来了解下vue路由两种模式的区别。
const router = createRouter({
history: createWebHistory(), // createWebHashHistory URL带#,createWebHistory URL不带#
routes: constantRoutes
});
1.hash 模式(默认)的访问URL中有 # 字符,history模式的URL没有带#,外观上history模式比hash模式好看些;
2.hash模式通过监听浏览器的onhashchange()事件变化,查找对应的路由规则;history模式是利用h5的history中新增的两个API pushState() 和 replaceState() 和一个事件onpopstate监听其URL变化;
3.hash模式能兼容到IE8,history模式 只能兼容到 IE10;
4.由于 hash 值变化不会导致浏览器向服务器发出请求,而且 hash 改变会触发 hashchange 事件(hashchange只能改变 # 后面的url片段);虽然hash路径出现在URL中,但是不会出现在HTTP请求中,对服务器完全没有影响,因此改变hash值不会重新加载页面,基本都是使用 hash 来实现前端路由的。
重点:hash模式在每次刷新页面时是直接更改“#”后的路径,history模式每次刷新会重新像服务器重新请求资源,但是服务器会把vue的路由地址当成文件路径访问(如: /pages/index),服务器又没有这个文件路径,且服务端没有配置相应的路由重定向,就会访问404,也就是本文开头提到的问题;history模式的好处是可以进行修改历史记录,并且不会立刻像后端发起请求。不过如果对于项目没有硬性标准要求,我们可以直接使用hash模式开发。
解决方案
为了处理这个问题,你需要配置服务器,使其在遇到 404 错误时始终返回 index.html
文件。这样 Vue Router 就可以接管并处理所有路由。
以下是针对不同服务器的解决方案:
1. 使用 Nginx
在 Nginx 中,可以通过修改配置文件来实现这一点。打开 Nginx 配置文件(通常是 /etc/nginx/nginx.conf
或 /etc/nginx/sites-available/default
),并添加如下配置:
server {
listen 80;
server_name your_domain_or_ip;
root /path/to/your/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# 其他配置...
}
2. 使用 Apache
在 Apache 中,可以使用 .htaccess
文件来实现这一点。创建或编辑 .htaccess
文件(位于项目的根目录),并添加如下配置:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
3. 使用 Express.js
如果使用 Node.js 和 Express.js 作为服务器,可以在服务器代码中添加一个 catch-all 路由来处理所有未匹配的请求:
const express = require('express');
const path = require('path');
const app = express();
const port = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'dist')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
总结
无论使用什么服务器,解决方案的核心是确保所有未匹配的请求都返回 index.html
,以便 Vue Router 可以处理客户端路由。这将确保在刷新页面时,不会出现 404 错误,并且应用可以正常加载。