根据编码的formData值设置节点请求标头

时间:2016-01-04 23:47:42

标签: javascript node.js encoding http-headers npm-request

我尝试使用request npm包向需要特殊标头的API发送HTTP POST,该标头由请求正文字符串的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模块处理后,但在请求之前实际发送,所以我可以构建哈希值并添加标题。

2 个答案:

答案 0 :(得分:0)

request使用form-data npm包对表单提交进行编码。该对象可通过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来计算哈希值。然后创建另一个form-data实例并将其传递给request

答案 1 :(得分: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(),甚至可能在内存中缓冲文件字段)。但是,它将取决于目标服务器是否支持预告片头(无论是解析它们还是实际上都使用它们)。