在 Hapijs 中如何获取原始请求正文的缓冲区?

4

使用body-parser + expressjs是可以的。但我的问题是:如何在Hapijs中获取原始请求体的缓冲区?

我说的是类似于body-parser npm包中这个函数的buf参数:verify(req,res, buf, encoding)

我需要它用于messenger-platform-samples示例中的这个函数:

function verifyRequestSignature(req, res, buf) {
  var signature = req.headers["x-hub-signature"];
  if (!signature) {
    console.error("Couldn't validate the signature.");
  } else {
    var elements = signature.split('=');
    var method = elements[0];
    var signatureHash = elements[1];
    var expectedHash = crypto.createHmac('sha1', APP_SECRET)
                             .update(buf)
                             .digest('hex');
    if (signatureHash != expectedHash) {
      throw new Error("Couldn't validate the request signature.");
    }
  }
}

编辑:我需要在我的中间件中使用此代码,使用server.ext(),像这样:

server.ext({
  type: 'onRequest',
  method: (request, reply) => {
    var signature = request.headers["x-hub-signature"];

    if (!signature) {
      console.error("Couldn't validate the signature.");
    } else {
      var elements = signature.split('=');
      var method = elements[0];
      var signatureHash = elements[1];

      var expectedHash = crypto.createHmac('sha1', APP_SECRET)
                              .update(request.payload)
                              .digest('hex');

      if (signatureHash != expectedHash) {
        throw new Error("Couldn't validate the request signature.");
      }
      return reply.continue();
    }
  }
});
2个回答

8
hapi@16.1.0 中,您可以通过以下方式获取原始缓冲区和原始标头:

这是如何获取原始缓冲区和原始标头的方法:

'use strict';

const Hapi = require('hapi');

const server = new Hapi.Server();
server.connection({
    host: 'localhost',
    port: 8000
});

server.route({
    method: 'POST',
    path:'/',
    handler: function (request, reply) {
        console.log(request.payload);
        console.log(request.raw.req.headers);
        return reply('hello world');
    },
    config: {
        payload: {
            output: 'data',
            parse: false
        }
    }
});

server.start((err) => {
    if (err) throw err;
    console.log('Server running at:', server.info.uri);
});

运行示例:

$ curl -X POST 'http://localhost:8000/' -d name=nehaljwani --trace-ascii /dev/stdout
Note: Unnecessary use of -X or --request, POST is already inferred.
== Info:   Trying 127.0.0.1...
== Info: TCP_NODELAY set
== Info: Connected to localhost (127.0.0.1) port 8000 (#0)
=> Send header, 148 bytes (0x94)
0000: POST / HTTP/1.1
0011: Host: localhost:8000
0027: User-Agent: curl/7.51.0
0040: Accept: */*
004d: Content-Length: 15
0061: Content-Type: application/x-www-form-urlencoded
0092:
=> Send data, 15 bytes (0xf)
0000: name=nehaljwani
== Info: upload completely sent off: 15 out of 15 bytes
<= Recv header, 17 bytes (0x11)
0000: HTTP/1.1 200 OK
<= Recv header, 40 bytes (0x28)
0000: content-type: text/html; charset=utf-8
<= Recv header, 25 bytes (0x19)
0000: cache-control: no-cache
<= Recv header, 20 bytes (0x14)
0000: content-length: 11
<= Recv header, 23 bytes (0x17)
0000: vary: accept-encoding
<= Recv header, 37 bytes (0x25)
0000: Date: Sun, 05 Mar 2017 07:51:14 GMT
<= Recv header, 24 bytes (0x18)
0000: Connection: keep-alive
<= Recv header, 2 bytes (0x2)
0000:
<= Recv data, 11 bytes (0xb)
0000: hello world
== Info: Curl_http_done: called premature == 0
== Info: Connection #0 to host localhost left intact
hello world

服务器输出:

Server running at: http://localhost:8000
<Buffer 6e 61 6d 65 3d 6e 65 68 61 6c 6a 77 61 6e 69>
{ host: 'localhost:8000',
  'user-agent': 'curl/7.51.0',
  accept: '*/*',
  'content-length': '15',
  'content-type': 'application/x-www-form-urlencoded' }

要访问原始缓冲区,您需要将其移动到路由前提条件中。因此,路由的配置看起来应该是这样的:

config: {
    pre: [
        {
            method: (request, reply) => {
                //signature verification steps
                return reply.continue();
            }
        }
    ],
    payload: {
        output: 'data',
        parse: false
    }
}

非常感谢。但是在我的处理程序中,我需要使用 request.payload,所以我必须自己解析它吗? - notme
1
@TrieuDang 不幸的是,是的。因为如果你将解析设置为 true,那么我找不到任何获取原始缓冲区的方法。它似乎被吞没了 :) - Nehal J Wani
但现在又出现了另一个问题,我想在中间件中使用这个缓冲区,而不是在处理程序中使用。我正在使用 server.ext() 来定义我的中间件,那么我该如何获取这个缓冲区呢? - notme
2
@TrieuDang 不,你无法在 .ext 中访问原始缓冲区。但是你可以在 route-prerequisites 中访问它。阅读:https://hapijs.com/api/16.1.0#route-prerequisites - Nehal J Wani
非常感谢。我现在有一个解决方案,我会尝试一下。但是如果您收到这个问题的另一个通知,请回来帮助我哈哈:D - notme
完成。谢谢您! - notme

0

我知道这个问题现在有点老了,但最近我也遇到了同样的问题,并且发现了一个解决方案,它不需要我放弃自动数据解析。

在插件的 onRequest 钩子中(您也可以直接在您感兴趣的请求上执行此操作),我有以下代码:

server.ext('onRequest', (request, h) => {
      const dataChunks: Buffer[] = [];

      request.raw.req.on('data', (chunk) => {
        dataChunks.push(chunk);
      });

      request.raw.req.on('end', () => {
        request.plugins['MyPlugin'] = {
          rawBody: Buffer.concat(dataChunks),
        };
      });

      return h.continue;
    });

后来,在preHandler钩子中,我可以从request.plugins['MyPlugin'].rawBody属性访问原始缓冲区,并以任何我认为合适的方式进行操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接