Quasar CLI with Webpack - @quasar/app-webpack

SSR 处理 404 和 500 错误

处理 SSR 模式的 404 和 500 错误的方式与其他的模式(SPA 等)有些不同,如果您打开了/src-ssr/middlewares/render.js,您会发现以下代码:

// src-ssr/middlewares/render.js

// 这个中间件需要在最后执行
// 因为他会捕获所有路由,并使用 Vue 渲染页面

export default ({ app, resolve, render, serve }) => {
  // 我们捕获所有的 Express 路由然后处理它
  // 通过 Vue 和 Vue Router 去渲染页面
  app.get(resolve.urlPath('*'), (req, res) => {
    res.setHeader('Content-Type', 'text/html')

    render({ req, res })
      .then(html => {
        // 发送渲染好的 html 页面给客户端
        res.send(html)
      })
      .catch(err => {
        // 处理渲染页面时发生的异常

        // 重定向到另一个 URL
        if (err.url) {
          if (err.code) {
            res.redirect(err.code, err.url)
          }
          else {
            res.redirect(err.url)
          }
        }
        // 处理 404 请求,Vue Router 没有找到的路由
        else if (err.code === 404) {
          // 只有当/src/routes 中没有定义"catch-all"路由时才会到达这里
          res.status(404).send('404 | Page Not Found')
        }
        // 我们也可以处理其他类型的错误
        // 如果处于开发模式,我们可以使用 Quasar CLI
        // 来显示一个带调用栈的漂亮的错误页面
        // 以及其他的提示信息
        else if (process.env.DEV) {
          // serve.error 只在开发模式下可用
          serve.error({ err, req, res })
        }
        // 当处于生产环境下时
        // 我们需要使用另一种方法通知客户端发生了错误
        // (出于安全的考虑,不能在生产模式下
        // 展示开发模式下同样的报错信息)
        else {
          // 渲染一个错误页面
          // 或者重定向到一个提前准备好的错误页面中
          // (提前定义在(/src/routes)中的错误页面)
          res.status(500).send('500 | Internal Server Error')
          // console.error(err.stack)
        }
      })
  })
}

上面的部分是在捕获其他可能的请求(如/public 目录、manifest.json 和 service worker 等)之后编写的。这是我们使用 Vue 和 Vue Router 渲染页面的地方。

注意事项

我们将讨论一些您需要注意的架构决策。选择最适合您的应用程序的内容。

404 错误

如果您在 Vue 路由 /src/router/routes.js 文件中定义了等效的 404 路由。(如下所示),则上述示例中的 if (err.code === 404) { 部分将永远不会触发,因为 Vue Router 已经处理了它。

// Vue Router 捕获 404 的示例
{ path: '/:catchAll(.*)*', component: () => import('pages/Error404.vue') }

500 错误

上述的/src-ssr/middlewares/render.js中可以看到,当服务端发生了渲染错误时,会返回一个简单的字符串给客户端(‘500 | Internal Server Error’),如果您想定制一个漂亮的错误页面代替:

  1. /src/router/routes.js 文件中添加一个特殊的路由,例如:
{ path: 'error500', component: () => import('pages/Error500.vue') }
  1. 编写一个 Vue 组件来处理这个页面,示例: /src/pages/Error500.vue
  2. 然后修改 /src-ssr/middlewares/render.js
if (err.url) { ... }
else if (err.code === 404) { ... }
else {
  // 捕获到一个 500 错误;
  // 准备重定向到第一步中定义的"error500"路由
  res.redirect(resolve.urlPath('error500'))
  // 记得挂载在 publicPath 下
  // keep account of publicPath though!
}

WARNING

您必须保证渲染 /error500 路由的时候不会发生 500 错误,否则,您的程序将进入无线循环。

避免这种情况的完美方法是直接从 /src-ssr/middlewares/render.js 文件中返回 500 错误页的 HTML(作为字符串):

res.status(500).send(`<html>....</html>`)