繁体   English   中英

如何使用 nginx 服务器处理 vuejs SPA 中的 404 错误请求

[英]How to handle 404 error request in vuejs SPA with nginx server

我已经设置了我的 vue-cli 版本 3 SPA,以便在我的 routes.js 文件中找不到的任何请求将默认为我的 404 视图,如官方文档中所示:

插入到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#警告

我认为它类似于 Node 解决方案 - 您应该在 nginx 配置中重复所有路由以正确返回 404 状态代码,主要思想是您应该在位置中使用“equals”修饰符并定义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 配置,但它有效。

我通过打破 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. 简单地使用新的 URL(例如/notfound )重新加载页面并不能解决问题,因为这意味着潜在的蜘蛛已经收到了 200。
  2. 简单地复制路线,是一个半解决方案。 这适用于永远不会改变的 URL,并通过检查 URL 结构的有效性。 例如,它可以检查books/123的图书ID 是否具有正确的格式,但它无法检查books/123确实存在于后端。

这里有两种方法可以解决上述问题

  1. 让 Nginx 向后端发出镜像子请求以检查资源是否确实存在。 然后总是返回 index.html 但带有来自子请求响应的状态。 这对于 Nginx 来说非常棘手,因为按照设计,它很难结合答案。
  2. 让后端 API 为Accept: text/html返回 index.html 。 然后 Nginx 只需要转发响应。

第一个解决方案对于不熟悉 Nginx 的人来说是一种痛苦。 它需要使用 OpenResty 获取 Lua,然后你会再次遇到 Nginx 工作方式的各种怪癖。 你最终会得到很多难以阅读的代码,如果你进一步想要引入缓存,这会变得更加困难。

第二种解决方案更简单。 唯一可能的负面影响是,如果您目前拥有该 API,则您无法从浏览器查看该 API。

nginx.config(当 API 在Accept: text/html时使用 index.html 响应Accept: text/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。 最后我们直接将响应返回给客户端。

这有以下好处:

  1. 它不依赖于 Nginx,因此它可以与任何反向代理一起使用。 最重要的是它不依赖代理服务器来拥有某些功能。
  2. 即使在没有运行 Nginx 的情况下也能在开发过程中工作。
  3. 易于编写测试。 您只需测试您的后端 API,以便在给定Accept: text/html为任何端点吐出index.html
  4. 不需要您使用每个新端点手动更新 Nginx 配置。

此外,您可以更改配置以使 Nginx 在内部遵循重定向,甚至可能不必查看后端 API 以获取永不更改的 URL。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM