【问题标题】:Node.js - get raw request body using ExpressNode.js - 使用 Express 获取原始请求正文
【发布时间】:2013-09-13 15:35:55
【问题描述】:

当我使用 Express 时,我的代码是:

app.use(express.bodyParser());

我如何获得原始请求正文

【问题讨论】:

标签: node.js express request


【解决方案1】:

2022 年

在每个 API 中获取 raw body 的最佳方法是将缓冲区转换为字符串。

app.use(
  express.json({
    limit: '5mb',
    verify: (req, res, buf) => {
      req.rawBody = buf.toString();
    },
  })
);

【讨论】:

    【解决方案2】:

    使用

    app.use(express.json());
    

    app.use(express.text());
    

    app.use(express.urlencoded());
    

    取决于您的原始格式

    【讨论】:

    • 这些与原始请求正文完全相反。
    【解决方案3】:
    // Change the way body-parser is used
    const bodyParser = require('body-parser');
    
    var rawBodySaver = function (req, res, buf, encoding) {
      if (buf && buf.length) {
        req.rawBody = buf.toString(encoding || 'utf8');
      }
    }
    app.use(bodyParser.json({ verify: rawBodySaver, extended: true }));
    
    
    
    
    // Now we can access raw-body any where in out application as follows
    request.rawBody;
    

    【讨论】:

      【解决方案4】:

      编辑 2: 正文解析器模块的 1.15.2 版引入了 raw mode,它将正文作为 Buffer 返回。默认情况下,它还会自动处理 deflate 和 gzip 解压缩。示例用法:

      var bodyParser = require('body-parser');
      app.use(bodyParser.raw(options));
      
      app.get(path, function(req, res) {
        // req.body is a Buffer object
      });
      

      默认情况下,options 对象具有以下默认选项:

      var options = {
        inflate: true,
        limit: '100kb',
        type: 'application/octet-stream'
      };
      

      如果您希望原始解析器解析 application/octet-stream 以外的其他 MIME 类型,则需要在此处进行更改。它还将支持通配符匹配,例如*/**/application


      注意:以下答案适用于 Express 4 之前的版本,其中中间件仍与框架捆绑在一起。现代等效的是body-parser 模块,必须单独安装。

      Express 中的rawBody 属性曾经可用,但自版本 1.5.1 起已删除。要获取原始请求正文,您必须在使用 bodyParser 之前放入一些中间件。你也可以阅读关于它的 GitHub 讨论here

      app.use(function(req, res, next) {
        req.rawBody = '';
        req.setEncoding('utf8');
      
        req.on('data', function(chunk) { 
          req.rawBody += chunk;
        });
      
        req.on('end', function() {
          next();
        });
      });
      app.use(express.bodyParser());
      

      该中间件将从实际数据流中读取,并将其存储在请求的rawBody 属性中。然后,您可以像这样访问原始正文:

      app.post('/', function(req, res) {
        // do something with req.rawBody
        // use req.body for the parsed body
      });
      

      编辑: 看来这个方法和bodyParser拒绝共存,因为一个会先消费请求流,导致哪个第二个永远不会触发end,因此永远不会调用next(),然后挂起你的应用程序。

      最简单的解决方案很可能是修改 bodyParser 的源,您可以在 Connect 的 JSON 解析器的 line 57 上找到它。这就是修改后的版本。

      var buf = '';
      req.setEncoding('utf8');
      req.on('data', function(chunk){ buf += chunk });
      req.on('end', function() {
        req.rawBody = buf;
        var first = buf.trim()[0];
        ...
      });
      

      你会在这个位置找到文件:

      /node_modules/express/node_modules/connect/lib/middleware/json.js.

      【讨论】:

      • 看来我们做不到。如果我添加了这些代码,则不会触发 \node_modules\express\node_modules\connect\lib\middleware\urlencoded.js 中的事件。 req.on("data"),req.on("end") 未触发.
      • 添加您的代码后,我使用此代码处理我的帖子 app.post("/ajax", function(req,res) { res.send('hello world,post'); } ) ;当我的请求内容类型为 application/x-www-form-urlencoded 时,服务器不会响应“hello world,post”
      • Connect 不是 Express 4 中的依赖项,因此不包含 Body Parser 模块。如果你仍然需要它,你会找到它here
      • @hexacyanide 您能否更新您的答案并包含对最新body-parser 中间件的引用?该模块现在包括raw-body-parser middleware。这对于正在寻找获取原始主体的方法的谷歌用户很有帮助。
      【解决方案5】:

      使用body-parser 解析正文:

      app.use(bodyParser.text());

      app.use(bodyParser.urlencoded());

      app.use(bodyParser.raw());

      app.use(bodyParser.json());

      即。如果您应该获取原始文本文件,请运行.text()

      这就是 body-parser 目前支持的

      【讨论】:

        【解决方案6】:

        这个解决方案对我有用:

        var rawBodySaver = function (req, res, buf, encoding) {
          if (buf && buf.length) {
            req.rawBody = buf.toString(encoding || 'utf8');
          }
        }
        
        app.use(bodyParser.json({ verify: rawBodySaver }));
        app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
        app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' }));
        

        当我使用带有req.on('data', function(chunk) { }); 的解决方案时,它不适用于分块的请求正文。

        【讨论】:

        【解决方案7】:

        我得到了一个与 bodyParser 配合得很好的解决方案,在 bodyParser 中使用 verify 回调。在这段代码中,我使用它来获取内容的 sha1 并获取原始正文。

        app.use(bodyParser.json({
            verify: function(req, res, buf, encoding) {
        
                // sha1 content
                var hash = crypto.createHash('sha1');
                hash.update(buf);
                req.hasha = hash.digest('hex');
                console.log("hash", req.hasha);
        
                // get rawBody        
                req.rawBody = buf.toString();
                console.log("rawBody", req.rawBody);
        
            }
        }));
        

        我是 Node.js 和 express.js 的新手(从字面上看是昨天开始的!),所以我想听听 cmets 对这个解决方案的看法。

        【讨论】:

        • 我真的很喜欢这个解决方案。我只包含了req.rawBody = buf.toString(); 并将其余部分从verify 函数中取出,因为这就是我所需要的,而且它工作得很好。无需更改 bodyParser 源代码!
        • +1 但我现在的问题是我需要一个异步函数来验证此请求之前是否已发送:/
        • 非常好。我可以建议req.rawBody = buf.toString(encoding);
        • 这将仅捕获 application/json 请求
        【解决方案8】:

        请注意其他答案,因为如果您希望还支持 json、urlencoded 等,它们将无法与 bodyParser 一起正常播放。要使其与 bodyParser 一起使用,您应该将处理程序设置为仅在 @987654321 上注册@ header(s) 你关心的,就像 bodyParser 本身一样。

        要将带有Content-Type: "text/plain" 的请求的原始正文内容转换为req.rawBody,您可以这样做:

        app.use(function(req, res, next) {
          var contentType = req.headers['content-type'] || ''
            , mime = contentType.split(';')[0];
        
          if (mime != 'text/plain') {
            return next();
          }
        
          var data = '';
          req.setEncoding('utf8');
          req.on('data', function(chunk) {
            data += chunk;
          });
          req.on('end', function() {
            req.rawBody = data;
            next();
          });
        });
        

        【讨论】:

        • +1。我尝试了上述解决方案之一,然后我所有的 GET 和 json 帖子都失败了。上述解决方案在技术上对于该问题是正确的,但如果您要处理具有多种形式的数据的更多样化的请求,则需要此解决方案。
        • 这里的数据是什么?是我们从 UI 发送的变量吗?
        • app.use(bodyParser.urlencoded({limit: '80mb', extended: true})); app.use(bodyParser.json({limit: '80mb'})); app.use(bodyParser.raw({type: 'application/octet-stream'})) 这也行。
        【解决方案9】:

        这是上面六氰化物答案的变体。该中间件还处理“数据”事件,但在调用“下一步”之前不会等待数据被使用。这样,这个中间件和 bodyParser 可以共存,并行消费流。

        app.use(function(req, res, next) {
          req.rawBody = '';
          req.setEncoding('utf8');
        
          req.on('data', function(chunk) { 
            req.rawBody += chunk;
          });
        
          next();
        });
        app.use(express.bodyParser());
        

        【讨论】:

        • 这似乎不适用于过早切断的长体。
        • 完美运行,救了我。谢谢。
        • 我确认这也适用于大文件。我尝试发送一个 1.5MB 的文本文件,并正确接收了整个数据。谢谢
        • @AdamLockhart - 你的请求被削减了多少?
        • @UpTheCreek,有一段时间了。不确定。我最新的东西没有使用这个sn-p,但是如果其他人报告没有问题,那可能是已经修复的错误。
        猜你喜欢
        • 2021-12-23
        • 2019-01-07
        • 2019-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多