如何使用nginx服务器处理vuejs SPA中的404错误请求
How to handle 404 error request in vuejs SPA with nginx server
我已经设置了我的 vue-cli 版本 3 SPA,这样在我的 routes.js 文件中找不到的任何请求都将默认为我的 404 视图,如官方 documentation 所示:
已插入 routes.js
文件底部附近:
{ // catches 404 errors
path: '*',
name: '404',
component: () => import(/* webpackChunkName: "NotFoundComponent" */ './views/NotFoundComponent.vue'),
},
已插入 nginx 配置文件:
location / {
try_files $uri $uri/ /index.html;
}
这成功提醒用户他们请求的页面不存在。
我的问题:
我希望错误 404 组件 return 404 响应 header(当前 return 是 200 状态代码)并将此错误记录到 nginx error.log 文件。我想这只能通过使用 nginx 配置来实现。有人实现了这个目标吗?
我注意到这个问题在 vue-cli 官方文档的下一页中得到了解决,但它只与 node express 服务器有关,与 nginx 无关:
https://router.vuejs.org/guide/essentials/history-mode.html#caveat
我认为它类似于 Node 解决方案 - 你应该在 nginx 配置中重复你的所有路由到 return 404 状态代码正确,主要思想是你应该在位置使用 "equals" 修饰符并将 error_page
定义为 return 相同的 index.html
文件,但状态代码为 404,例如:
server {
listen 80;
server_name localhost;
root /my/dir/with/app
error_page 404 /index.html;
location = / {
try_files $uri $uri/ /index.html;
}
location = /books {
try_files $uri $uri/ /index.html;
}
# example nested page
location = /books/authors {
try_files $uri $uri/ /index.html;
}
# example dynamic route to access book by id
location ~ /books/\d+$ {
try_files $uri $uri/ /index.html;
}
}
可能这个配置可以简化或改进,因为我不是很擅长 nginx 配置但它有效。
我通过脱离 Vue 生态系统以简单的方式解决了这个问题,否则它不会工作或需要很多努力。
在您的 Vue 路由器中创建以下路由:
{
path: '*',
name: 'PageNotFound',
component: PageNotFound
}
PageNotFound
组件应具有以下代码:
<script>
export default {
name: 'PageNotFound',
created() {
window.location.href = "/404/"
}
}
</script>
nginx 配置在获取 /404/
路由时应该 return 404:
server {
...
location ~ ^/404/$ {
return 404;
}
...
}
我认为它不适用于服务器端渲染环境。在这种情况下,您可能需要将包含 window.location.href
的语句放在 mounted
方法中。
对于遇到此问题的任何人,让您免去数小时的头痛。
以上答案的注意事项
- 简单地用新的 URL(例如
/notfound
)重新加载页面并不能解决问题,因为这意味着潜在的蜘蛛已经收到 200.
- 简单的复制路由,就是一个half-solution。这适用于永远不会改变的 URLs,并通过检查 URL 结构的有效性。因此,例如它可以检查
books/123
中的图书 ID 是否具有正确的格式,但它无法检查 books/123
是否确实存在于后端。
这里有两种方法可以解决上述问题
- 让Nginx 向后端发出镜像子请求以检查资源是否实际存在。然后 always return index.html 但状态来自子请求的响应。这对于 Nginx 来说非常棘手,因为在设计上它很难组合答案。
Accept: text/html
的后端 API 到 return index.html。然后 Nginx 只需要转发响应。
第一个解决方案对于不熟悉 Nginx 的人来说是个麻烦。它需要使用 OpenResty 获得 Lua 然后你将再次 运行 了解 Nginx 工作方式的各种怪癖。你最终会得到很多 hard-to-read 代码,如果你 further-more 想引入缓存,这会变得更加困难。
第二个解决方案更简单。唯一可能的负面影响是,这意味着您无法从浏览器中查看 API,如果您当前已经存在的话。
nginx.config(当 API 在 Accept: text/html
上用 index.html 响应时)
location / {
try_files $uri $uri/ @fallback;
}
location @fallback {
rewrite ^(.*) /api break;
proxy_set_header "Accept" "text/html";
proxy_pass http://localhost:8000;
}
在这种情况下,Nginx 将首先尝试提供该文件,如果在本地找不到它,它将通过回退。
在回退中,我们重写 URI 以匹配后端服务器的期望。在此示例中,我将 api/
添加到每个请求的前面。然后我添加 header Accept: text/html
以便后端 API 将响应 index.html 而不是 JSON。最后我们直接将响应返回给客户端。
这有以下好处:
- 它不依赖于 Nginx,因此它可以与任何反向代理一起工作。最重要的是它不依赖代理服务器而具有某些功能。
- 即使在没有 Nginx 运行ning 的开发过程中也能工作。
- 易于编写测试。您只需要测试您的后端 API 在为任何端点提供
Accept: text/html
时吐出 index.html
。
- 不需要您为每个新端点手动更新 Nginx 配置。
此外,您可以更改配置以使 Nginx 在内部遵循重定向,甚至可能不必查看后端 API 以获取永远不会更改的 URL。
我已经设置了我的 vue-cli 版本 3 SPA,这样在我的 routes.js 文件中找不到的任何请求都将默认为我的 404 视图,如官方 documentation 所示:
已插入 routes.js
文件底部附近:
{ // catches 404 errors
path: '*',
name: '404',
component: () => import(/* webpackChunkName: "NotFoundComponent" */ './views/NotFoundComponent.vue'),
},
已插入 nginx 配置文件:
location / {
try_files $uri $uri/ /index.html;
}
这成功提醒用户他们请求的页面不存在。
我的问题:
我希望错误 404 组件 return 404 响应 header(当前 return 是 200 状态代码)并将此错误记录到 nginx error.log 文件。我想这只能通过使用 nginx 配置来实现。有人实现了这个目标吗?
我注意到这个问题在 vue-cli 官方文档的下一页中得到了解决,但它只与 node express 服务器有关,与 nginx 无关: https://router.vuejs.org/guide/essentials/history-mode.html#caveat
我认为它类似于 Node 解决方案 - 你应该在 nginx 配置中重复你的所有路由到 return 404 状态代码正确,主要思想是你应该在位置使用 "equals" 修饰符并将 error_page
定义为 return 相同的 index.html
文件,但状态代码为 404,例如:
server {
listen 80;
server_name localhost;
root /my/dir/with/app
error_page 404 /index.html;
location = / {
try_files $uri $uri/ /index.html;
}
location = /books {
try_files $uri $uri/ /index.html;
}
# example nested page
location = /books/authors {
try_files $uri $uri/ /index.html;
}
# example dynamic route to access book by id
location ~ /books/\d+$ {
try_files $uri $uri/ /index.html;
}
}
可能这个配置可以简化或改进,因为我不是很擅长 nginx 配置但它有效。
我通过脱离 Vue 生态系统以简单的方式解决了这个问题,否则它不会工作或需要很多努力。
在您的 Vue 路由器中创建以下路由:
{
path: '*',
name: 'PageNotFound',
component: PageNotFound
}
PageNotFound
组件应具有以下代码:
<script>
export default {
name: 'PageNotFound',
created() {
window.location.href = "/404/"
}
}
</script>
nginx 配置在获取 /404/
路由时应该 return 404:
server {
...
location ~ ^/404/$ {
return 404;
}
...
}
我认为它不适用于服务器端渲染环境。在这种情况下,您可能需要将包含 window.location.href
的语句放在 mounted
方法中。
对于遇到此问题的任何人,让您免去数小时的头痛。
以上答案的注意事项
- 简单地用新的 URL(例如
/notfound
)重新加载页面并不能解决问题,因为这意味着潜在的蜘蛛已经收到 200. - 简单的复制路由,就是一个half-solution。这适用于永远不会改变的 URLs,并通过检查 URL 结构的有效性。因此,例如它可以检查
books/123
中的图书 ID 是否具有正确的格式,但它无法检查books/123
是否确实存在于后端。
这里有两种方法可以解决上述问题
- 让Nginx 向后端发出镜像子请求以检查资源是否实际存在。然后 always return index.html 但状态来自子请求的响应。这对于 Nginx 来说非常棘手,因为在设计上它很难组合答案。
Accept: text/html
的后端 API 到 return index.html。然后 Nginx 只需要转发响应。
第一个解决方案对于不熟悉 Nginx 的人来说是个麻烦。它需要使用 OpenResty 获得 Lua 然后你将再次 运行 了解 Nginx 工作方式的各种怪癖。你最终会得到很多 hard-to-read 代码,如果你 further-more 想引入缓存,这会变得更加困难。
第二个解决方案更简单。唯一可能的负面影响是,这意味着您无法从浏览器中查看 API,如果您当前已经存在的话。
nginx.config(当 API 在 Accept: text/html
上用 index.html 响应时)
location / {
try_files $uri $uri/ @fallback;
}
location @fallback {
rewrite ^(.*) /api break;
proxy_set_header "Accept" "text/html";
proxy_pass http://localhost:8000;
}
在这种情况下,Nginx 将首先尝试提供该文件,如果在本地找不到它,它将通过回退。
在回退中,我们重写 URI 以匹配后端服务器的期望。在此示例中,我将 api/
添加到每个请求的前面。然后我添加 header Accept: text/html
以便后端 API 将响应 index.html 而不是 JSON。最后我们直接将响应返回给客户端。
这有以下好处:
- 它不依赖于 Nginx,因此它可以与任何反向代理一起工作。最重要的是它不依赖代理服务器而具有某些功能。
- 即使在没有 Nginx 运行ning 的开发过程中也能工作。
- 易于编写测试。您只需要测试您的后端 API 在为任何端点提供
Accept: text/html
时吐出index.html
。 - 不需要您为每个新端点手动更新 Nginx 配置。
此外,您可以更改配置以使 Nginx 在内部遵循重定向,甚至可能不必查看后端 API 以获取永远不会更改的 URL。