nuxt2如何在nuxt.config.js中直接捕获服务端错误?

如题,项目前端是nuxt2做的,现在遇到如下问题
当通过非正常编码编码后的url 访问的时候, pm2日志中报错 "URI malformed"
探究了一下,错误是因为 /node_moduels/@nuxt/server/dist/server.js 文件中的

const nuxtMiddleware = ({ options, nuxt, renderRoute, resources }) => async function nuxtMiddleware (req, res, next) {
  // Get context
  const context = utils.getContext(req, res);

  try {
    const url = decodeURI(req.url); //这里
    res.statusCode = 200;
    const result = await renderRoute(url, context);

    // If result is falsy, call renderLoading
    if (!result) {
      await nuxt.callHook('server:nuxt:renderLoading', req, res);
      return
    }

    await nuxt.callHook('render:route', url, result, context);
    const {
      html,
      cspScriptSrcHashes,
      error,
      redirected,
      preloadFiles
    } = result;

    if (redirected && context.target !== utils.TARGETS.static) {
      await nuxt.callHook('render:routeDone', url, result, context);
      return html
    }
    if (error) {
      res.statusCode = context.nuxt.error.statusCode || 500;
    }

    if (options.render.csp && cspScriptSrcHashes) {
      const { allowedSources, policies } = options.render.csp;
      const isReportOnly = !!options.render.csp.reportOnly;
      const cspHeader = isReportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy';

      res.setHeader(cspHeader, getCspString({ cspScriptSrcHashes, allowedSources, policies, isReportOnly }));
    }

    // Add ETag header
    if (!error && options.render.etag) {
      const { hash } = options.render.etag;
      const etag = hash ? hash(html, options.render.etag) : generateETag__default['default'](html, options.render.etag);
      if (fresh__default['default'](req.headers, { etag })) {
        res.statusCode = 304;
        await nuxt.callHook('render:beforeResponse', url, result, context);
        res.end();
        await nuxt.callHook('render:routeDone', url, result, context);
        return
      }
      res.setHeader('ETag', etag);
    }

    // HTTP2 push headers for preload assets
    if (!error && options.render.http2.push) {
      // Parse resourceHints to extract HTTP.2 prefetch/push headers
      // https://w3c.github.io/preload/#server-push-http-2
      const { shouldPush, pushAssets } = options.render.http2;
      const { publicPath } = resources.clientManifest;

      const links = pushAssets
        ? pushAssets(req, res, publicPath, preloadFiles)
        : defaultPushAssets(preloadFiles, shouldPush, publicPath, options);

      // Pass with single Link header
      // https://blog.cloudflare.com/http-2-server-push-with-multiple-assets-per-link-header
      // https://www.w3.org/Protocols/9707-link-header.html
      if (links.length > 0) {
        res.setHeader('Link', links.join(', '));
      }
    }

    // Send response
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.setHeader('Accept-Ranges', 'none'); // #3870
    res.setHeader('Content-Length', Buffer.byteLength(html));
    await nuxt.callHook('render:beforeResponse', url, result, context);
    res.end(html, 'utf8');
    await nuxt.callHook('render:routeDone', url, result, context);
    return html
  } catch (err) {
    if (context && context.redirected) {
      consola__default['default'].error(err);
      return err
    }

    if (err.name === 'URIError') { //这里
      err.statusCode = 400;
    }
    next(err);
  }
};

其中

const url = decodeURI(req.url);

对url无法进行解析,导致的.

需求是想在遇到"URI malformed"错误的时候,直接跳首页,目前采用了两种做法解决

第一种:

在nuxt.config.js文件中,增加 serverMiddleware 配置项

serverMiddleware: [
    (req, res, next) => {
      // 自定义中间件逻辑...
      try {
        //尝试解析url
        decodeURIComponent(req.url)
        //往下继续执行
        next();
      } catch {
        //解析错误就跳转
        res.writeHead(302, {
          Location: '/'
        });
        res.end();

      }
    }
  ],

这样可以解决,但是无法阻止server.js 文件会对url再次进行解析,这样比较消耗资源

第二种:

直接修改 /node_moduels/@nuxt/server/dist/server.js 文件

if (err.name === 'URIError') {
      err.statusCode = 400;
    }

中加入:

if (err.name === 'URIError') {
      err.statusCode = 400;
      //新加
      res.writeHead(302, { Location: '/' })
      //新加
      return res.end()
    }

这样也能起到效果,但是这样就直接修改了核心代码

第三种:

使用nuxt.config.js 中的hook,示例如下

hooks: {
    render: {
        errorMiddleware(app) {
        app.use((error, req, res, next) => {
            res.writeHead(302, {
                Location: '/',
            })
            res.end()
        })
    },
},

这样也可以,似乎更恰当一些
但是对于负载来说, 是重定向到首页好,还是直接返回错误页,还是直接返回错误提示更好呢?

阅读 1.7k
avatarAI BotBETA

对于你的问题,有一种方法可以在不修改Nuxt.js核心代码或不使用自定义中间件的情况下解决。

你可以尝试在nuxt.config.js中捕获全局错误,并在出现"URI malformed"错误时进行特殊处理。代码如下:

export default {
  // ...
  error: {
    // Here we check for the 'URI malformed' error and handle it specifically
    handler (err, ctx) {
      if (err.name === 'URIError') {
        ctx.redirect('/')
      } else {
        // If it's not a 'URIError', let Nuxt handle it as usual
        ctx.error(err)
      }
    }
  }
  // ...
}

这样,当在服务端发生"URI malformed"错误时,Nuxt 会自动重定向到首页。在其他类型的错误中,Nuxt 将按照其默认的错误处理机制进行处理。

这种方法的好处是不会修改 Nuxt 的核心代码,也不会使用自定义中间件,因此不会增加额外的性能开销。同时,它也能够捕获所有在服务端发生的"URI malformed"错误,而不仅仅是在/node_moduels/@nuxt/server/dist/server.js文件中的那一个。

希望这个方法能够解决你的问题。

1 个回答
// nuxt.config.js
export default {
  serverMiddleware: [
    (req, res, next) => {
      try {
        decodeURIComponent(req.url);
        next();
      } catch (err) {
        if (err instanceof URIError) {
          req.url = '/'; // 修改req.url成一个有用的URL
          res.writeHead(302, { Location: '/' });
          res.end();
        } else {
          next(err);
        }
      }
    },
  ],
  // ...其他配置
};
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进