如何使用 nginx 服务器处理 vuejs SPA 中的 404 错误请求
Posted
技术标签:
【中文标题】如何使用 nginx 服务器处理 vuejs SPA 中的 404 错误请求【英文标题】:How to handle 404 error request in vuejs SPA with nginx server 【发布时间】:2019-02-27 11:22:24 【问题描述】:我已经设置了我的 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 组件返回 404 响应标头(它当前返回 200 状态代码)并将此错误记录到 nginx error.log 文件中。我想这只能通过使用 nginx 配置来实现。有人实现了这个目标吗?
我注意到这个问题在 vue-cli 官方文档的以下页面中得到了解决,但它只与 node express 服务器有关,而不是 nginx: https://router.vuejs.org/guide/essentials/history-mode.html#caveat
【问题讨论】:
试试这个try_files $uri $uri/ /index.html =404;
在这篇文章中查看我的答案:***.com/a/62651493/2951619
【参考方案1】:
我认为它类似于 Node 解决方案 - 您应该在 nginx 配置中重复所有路由以正确返回 404 状态代码,主要思想是您应该在位置使用“等于”修饰符并定义 error_page
以返回相同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 配置,但它可以工作。
【讨论】:
这是有道理的。如果有效,我会尝试并标记为已回答。谢谢麦克斯! 注意/books/666
将给出 200,无论它是否存在。必须有一种方法可以在转发响应之前检查来自应用服务器的响应。【参考方案2】:
我通过脱离 Vue 生态系统以简单的方式解决了这个问题,否则它将无法工作或需要付出很多努力。
在您的 Vue 路由器中创建以下路由:
path: '*',
name: 'PageNotFound',
component: PageNotFound
PageNotFound
组件应具有以下代码:
<script>
export default
name: 'PageNotFound',
created()
window.location.href = "/404/"
</script>
nginx 配置在获取/404/
路由时应返回 404:
server
...
location ~ ^/404/$
return 404;
...
我认为它不会在服务器端渲染环境中工作。在这种情况下,您可能需要将包含window.location.href
的语句放入mounted
方法中。
【讨论】:
这在某些情况下很好。我只看到两个问题:(1)解析为 404 的 URL,在地址栏中不可见,(2)重定向发生得很晚,在浏览器已经收到初始 200 之后。这可能会使爬虫感到困惑。 【参考方案3】:对于遇到此问题并为您节省数小时头痛的人。
以上答案的注意事项
-
仅使用新 URL(例如
/notfound
)重新加载页面并不能解决问题,因为这意味着潜在的蜘蛛已经收到 200。
简单地复制路线,是一个半解决方案。这适用于永远不会更改的 URL,并通过检查 URL 结构的有效性。例如,它可以检查books/123
中的图书id 是否具有正确的格式,但它不能检查books/123
是否确实存在于后端。
这里有两种方法可以解决上述问题
-
让 Nginx 向后端发出镜像子请求,以检查资源是否实际存在。然后 always 返回 index.html 但带有来自子请求响应的状态。这对于 Nginx 来说非常棘手,因为从设计上来说,它很难组合答案。
让后端 API 为
Accept: text/html
返回 index.html。然后 Nginx 只需要转发响应。
第一个解决方案对于不熟悉 Nginx 的人来说是一件很痛苦的事情。它需要使用 OpenResty 获取 Lua,然后你会再次遇到 Nginx 工作方式的各种怪癖。您最终会得到很多难以阅读的代码,如果您还想引入缓存,这将变得更加困难。
第二种解决方案更简单。唯一可能的负面影响是这意味着如果您当前拥有该 API,则无法从浏览器查看 API。
nginx.config(当 API 响应 Accept: text/html
上的 index.html 时)
location /
try_files $uri $uri/ @fallback;
location @fallback
rewrite ^(.*) /api$1 break;
proxy_set_header "Accept" "text/html";
proxy_pass http://localhost:8000;
在这种情况下,Nginx 将首先尝试提供该文件,如果在本地找不到它,它将通过后备。
在回退中,我们重写 URI 以匹配后端服务器的期望。在此示例中,我在每个请求前添加 api/
。然后我添加标题Accept: text/html
,以便后端 API 将使用 index.html 而不是 JSON 进行响应。最后我们直接将响应返回给客户端。
这有以下好处:
-
它不依赖于 Nginx,因此它可以与任何反向代理一起工作。最重要的是它不依赖代理服务器来拥有某些功能。
即使在没有运行 Nginx 的情况下在开发期间也能正常工作。
易于编写测试。您只需测试您的后端 API 以在为任何端点提供
Accept: text/html
时吐出 index.html
。
不需要您为每个新端点手动更新 Nginx 配置。
此外,您可以更改配置以使 Nginx 在内部遵循重定向,甚至可能不必查看后端 API 以获取永远不会更改的 URL。
【讨论】:
以上是关于如何使用 nginx 服务器处理 vuejs SPA 中的 404 错误请求的主要内容,如果未能解决你的问题,请参考以下文章
如何在 VueJs 组件中对 oembed javascript 标记进行整数处理?
如何在 vuejs 中隔离父元素和子元素之间的单击事件处理程序