1

我正在尝试使用 npm 包将 HTTP POST 发送request到需要特殊标头的 API,该标头由请求正文的字符串表示的 base64 编码的 MD5 哈希组成。

生成 MD5 哈希的代码:

function md5(val) {
    val = val || '';
    return crypto.createHash('md5').update(val).digest('base64');
}

当没有 formData 时,对于 GET 或 DELETE 请求,我应该使用的值是一个空字符串,效果很好。API 接受标头并返回请求的数据。

不幸的是,当使用该formData选项发布文件时,该对象正在由request模块编码。因此,当服务器将我的 MD5 哈希与最终收到的正文进行比较时,它不匹配并引发错误。

我需要的简化请求:

var formData = {
    left: 0,
    top: 0,
    width: 0,
    height: 0,
    profileImage: fs.readFileSync(__dirname + '/test_image.jpg')
};

var reqOptions = {
    url: 'https://example.com/user/1234/profile-image',
    method: 'POST,
    json: true,
    headers: {
        'Content-MD5': md5(formData)
    },
    formData: formData
}

request(reqOptions, function(err, response, body) {
    //process the response...
});

上面的例子会抛出一个错误,因为 formData 变量是一个对象,而crypto模块需要一个字符串。我开始手动编写代码以将 formData 对象转换为字符串,但是当模块已经完成编码所有表单值的所有逻辑时,重写所有逻辑似乎有点荒谬request

我正在寻找一种可靠的方法来获取精确的编码表单内容,在它们被request模块处理之后,但在请求实际发送之前,所以我可以构建哈希值并添加标题。

4

2 回答 2

0

request使用form-datanpm 包对表单提交进行编码。该对象可通过 访问request.form()。您应该能够将其通过管道传输到 md5 哈希实例中:

var formData = r.form();
var hash = crypto.createHash('md5');
hash.setEncoding('hex');
form.on('end', function() {
    hash.end();
    console.log('hash is', hash.read());
    // submit request here
});

如果您流式传输form到 md5 哈希然后request尝试再次使用相同的流,则可能会出现问题。在这种情况下,需要、实例化和填充form-data自己来计算哈希。然后创建另一个表单数据实例并将其传递给request.

于 2016-01-05T01:13:22.467 回答
0

您可以通过以下方式手动执行此操作:

var crypto = require('crypto');
var FormData = require('form-data');

var form = new FormData();
form.append('left', 0);
form.append('top', 0);
form.append('width', 0);
form.append('height', 0);
form.append('profileImage', fs.readFileSync(__dirname + '/test_image.jpg'));

var rawChunks = [];
var hash = crypto.createHash('md5');
form.on('data', function(chunk) {
  rawChunks.push(chunk);
  hash.update(chunk);
}).on('end', function() {
  var headers = form.getHeaders();
  headers['Content-MD5'] = hash.digest('base64');
  var req = request({
    url: 'https://example.com/user/1234/profile-image',
    method: 'POST',
    headers: headers
  }, function(err, res, body) {
    // Do something with response
  });
  for (var i = 0; i < rawChunks.length; ++i)
    req.write(rawChunks[i]);
  req.end();
});

另一种可能的替代方法可能是使用分块编码并Content-MD5作为 HTTP 尾标(出现在正文之后的标头)传递。fs.readFileSync()这将允许您防止在内存中缓冲生成的表单数据(如果您决定更改为,甚至可能在内存中缓冲文件字段fs.createReadStream())。然而,这一切都取决于目标服务器是否支持尾部标头(无论是解析它们还是实际使用它们)。

于 2016-01-05T01:30:35.140 回答