【问题标题】:Catch express bodyParser error捕捉快递 bodyParser 错误
【发布时间】:2013-03-27 00:10:27
【问题描述】:

我想在发送 json 对象时从 bodyParser() 中间件捕获错误,但它无效,因为我想发送自定义响应而不是通用 400 错误。

这就是我所拥有的,并且有效:

app.use (express.bodyParser ());
app.use (function (error, req, res, next){
    //Catch bodyParser error
    if (error.message === "invalid json"){
        sendError (res, myCustomErrorMessage);
    }else{
        next ();
    }
});

但这对我来说似乎是一种非常丑陋的方法,因为我正在比较可能在未来快速版本中更改的错误消息。还有其他方法可以捕获 bodyParser() 错误吗?

编辑:

这是请求正文包含无效json时的错误:

{
  stack: 'Error: invalid json\n    at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)\n    at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)\n    at IncomingMessage.EventEmitter.emit (events.js:92:17)\n    at _stream_readable.js:872:14\n    at process._tickDomainCallback (node.js:459:13)',
  arguments: undefined,
  type: undefined,
  message: 'invalid json',
  status: 400
}

漂亮的打印堆栈:

Error: invalid json
    at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)
    at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)
    at IncomingMessage.EventEmitter.emit (events.js:92:17)
    at _stream_readable.js:872:14
    at process._tickDomainCallback (node.js:459:13)

【问题讨论】:

    标签: javascript node.js express


    【解决方案1】:

    我认为你最好的选择是检查SyntaxError

    app.use(function (error, req, res, next) {
      if (error instanceof SyntaxError) {
        sendError(res, myCustomErrorMessage);
      } else {
        next();
      }
    });
    

    【讨论】:

    • 这不起作用,因为它不是语法错误。查看问题更新。
    • @GabrielLlamas 在最新版本的 Express (4.6.1) 中,bodyParser 模块不再是内置的,它已被移动到它自己的 module 中,这确实引发了 @ 987654325@ 用于格式错误的 JSON。
    • 但是,如果请求正文太大,您将收到错误而不是语法错误。例如:{ [Error: request entity too large] type: 'entity.too.large', message: 'request entity too large', statusCode: 413, status: 413, expected: 322350, length: 322350, limit: 102400 }
    • 只检查instanceof SyntaxError,然后检查instanceof Error,或者同样对待它们。问题:如果解析JSON的时候出现错误,error就为true,否则为false-y,对吧?
    • @WillBrickner error 将永远在那里,处理程序在发生错误时调用。但是错误可以是任何东西,它是一个通用的 Express 错误处理程序。
    【解决方案2】:

    来自@alexander 的回答,但有一个使用示例

    app.use((req, res, next) => {
        bodyParser.json({
            verify: addRawBody,
        })(req, res, (err) => {
            if (err) {
                console.log(err);
                res.sendStatus(400);
                return;
            }
            next();
        });
    });
    
    function addRawBody(req, res, buf, encoding) {
        req.rawBody = buf.toString();
    }
    

    【讨论】:

    • 嗨,很清楚,但有没有办法让它更短?是否需要验证参数?
    • 我不确定,也许我会再看一下文档,看看是否有更短的方法
    【解决方案3】:

    好的,找到了:

    bodyParser() 是 json()、urlencoded() 和 multipart() 的便捷函数。我只需要调用 json(),捕获错误并调用 urlencoded() 和 multipart()。

    bodyParser source

    app.use (express.json ());
    app.use (function (error, req, res, next){
        //Catch json error
        sendError (res, myCustomErrorMessage);
    });
    
    app.use (express.urlencoded ());
    app.use (express.multipart ());
    

    【讨论】:

    • 这不是解决方案。您没有考虑到在此代码之前可能是另一个中间件。如果你以这种方式捕捉到一些异常,它可能会导致不可预测的状态。至少最好写:app.use(function (error, req, res, next) { /* Shutdown node */ }; app.use(bodyParser.json()); app.use(function(error, req, res, next) { /* if err.status == 4** then handle json error =&gt; res.status(400).send(), else shutdown node */ });
    • DANGER DANGER,正如@Dao 所说,这会捕获上述中间件中的任何错误。不安全
    【解决方案4】:

    我所做的只是:

    app.use(bodyParser.json({ limit: '10mb' }))
    // body parser error catcher
    app.use((err, req, res, next) => {
      if (err) {
        res.status(400).send('error parsing data')
      } else {
        next()
      }
    })
    

    【讨论】:

    • 因为我也在使用 bodyParser.json()(现在已弃用),这对我来说是完美的。
    • 我很高兴它对你有用!
    【解决方案5】:

    所有错误都包含从 1.18.0 版本开始的类型属性。对于解析失败,err.type === 'entity.parse.failed'。

    app.use(function (error, req, res, next) {
    if (error.type === 'entity.parse.failed') {
     sendError(res, myCustomErrorMessage);
    } else {
     next();
    }
    });
    

    【讨论】:

    • 不错的答案。但是 sendError 函数是从哪里来的呢?
    【解决方案6】:

    我发现检查 SyntaxError 是不够的,因此我这样做了:

    if (err instanceof SyntaxError &&
      err.status >= 400 && err.status < 500 &&
      err.message.indexOf('JSON') !== -1) {
        // process filtered exception here
    }
    

    【讨论】:

    • indexOf 使用错误。如果在 javascript 中没有找到它,它将返回 -1。唯一不起作用的方法是 JSON 在字符串中的第一个。应该是err.message.indexOf('JSON') !== -1
    【解决方案7】:

    创建新模块“hook-body-parser.js” 在这里用 body parser 钩住所有东西

    const bodyParser = require("body-parser");
    
    module.exports = () => {
      return [
        (req, res, next) => {
          bodyParser.json()(req, res, (error) => {
            if (error instanceof SyntaxError) {
              res.sendStatus(400);
            } else {
              next();
            }
          });
        },
        bodyParser.urlencoded({ extended: true }),
      ];
    };
    

    并像这样使用 over express

    ... app.use(hookBodyParser()) ...

    【讨论】:

      【解决方案8】:

      例如,如果您想捕获 body-parsr 抛出的所有错误 entity.too.largeencoding.unsupported

      在你的 body-parser 初始化之后放置这个中间件

      $ npm i express-body-parser-error-handler
      

      https://www.npmjs.com/package/express-body-parser-error-handler

      例如:

      const bodyParserErrorHandler = require('express-body-parser-error-handler')
      const { urlencoded, json } = require('body-parser')
      const express = require('express')
      const app = express();
      router.route('/').get(function (req, res) {
          return res.json({message:"?"});
      });
      
      // body parser initilization
      app.use('/', json({limit: '250'}));
      
      // body parser error handler
      app.use(bodyParserErrorHandler());
      app.use(router);
      ...
      

      【讨论】:

        【解决方案9】:
        (bodyParser, req, res) => new Promise((resolve, reject) => {
            try {
                bodyParser(req, res, err => {
                    if (err instanceof Error) {
                        reject(err);
                    } else {
                        resolve();
                    }
                });
            } catch (e) {
                reject(e);
            }
        })
        

        防弹。面向未来。 WTFPL 许可。也很有用 w/ async/await。

        【讨论】:

        • 此后如何将此功能作为中间件插入我的应用程序?我将实际响应错误的代码放在哪里?这是在做什么?
        • 请解释如何将其集成到 express 应用程序中以及它是如何工作的。
        猜你喜欢
        • 2010-12-05
        • 2013-10-12
        • 1970-01-01
        • 2020-04-02
        • 2014-03-25
        • 2018-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多