在JavaScript中生成用于文件上载的HTTP多部分主体

Jag*_*agi 8 javascript http file http-headers meteor

我正在尝试在JavaScript中构建HTTP多部分表单数据(在服务器上为Meteor.js HTTP请求).

这是发送POST请求的Meteor代码.

var res = HTTP.post(url, {
  headers: formatted.headers,
  content: formatted.content
});
Run Code Online (Sandbox Code Playgroud)

我正在使用此代码准备标题和内容.

function MultipartFormData(parts) {
  var boundary = (new Date()).getTime();
  var bodyParts = [];

  _.each(parts, function (value, key) {
    value.data = (new Buffer(value.data)).toString('binary');

    bodyParts.push(
      '---------------------------' + boundary,
      'Content-Disposition: form-data; name="' + key + '"; filename="' + value.filename + '"',
      'Content-Type: ' + value.contentType,
      '',
      value.data);
  });

  bodyParts.push('---------------------------' + boundary + '--', '');

  var bodyString = bodyParts.join('\r\n');

  return {
    content: bodyString,
    headers: {
      'Content-Type': 'multipart/form-data; boundary=' + '---------------------------' + boundary,
      'Content-Length': bodyString.length
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

文件详情:

key = 'file'
value.filename = 'file.png'
value.contentType = 'image/png'
value.data is an Uint8Array
Run Code Online (Sandbox Code Playgroud)

服务器无法处理此请求.当我使用标准的Node.js请求对象和使用相同数据的FormBuilder时,一切正常.我只是在两个服务器之间请求http连接.谁能告诉我我的代码有什么问题?我不是HTTP协议的专家,我只有关于生成HTTP请求内容的信息.

还有一件事.我已经尝试将Uint8Array转换为Buffer,ArrayBuffer,String,但它也无法正常工作.

编辑:

我在Firefox和我的应用程序中发送相同的文件时测试了什么是http正文:

火狐:

Content-Type: multipart/form-data; boundary=---------------------------19039834425958857471335503868
Content-Length: 299

-----------------------------19039834425958857471335503868
Content-Disposition: form-data; name="file"; filename="test.png"
Content-Type: image/png

PNG


IHDR

·ü]þPLTEÿâ  7
IDAT×cÀÚqÅIEND®B`
-----------------------------19039834425958857471335503868--
Run Code Online (Sandbox Code Playgroud)

我的应用:

Content-Type: multipart/form-data; boundary=---------------------------1408816255735
Content-Length: 263

---------------------------1408816255735
Content-Disposition: form-data; name="file"; filename="test.png"
Content-Type: image/png

PNG


IHDR

·ü]þPLTEÿâ      7
IDA×cÀ
                                 ÚqÅIEND®B`
---------------------------1408816255735--
Run Code Online (Sandbox Code Playgroud)

它有点不同但我不知道这种差异的来源是什么.

编辑2

服务器响应是: Error: failed [400] Invalid multipart request with 0 mime parts.

编辑3

生成这样的身体时:

Content-Type: multipart/form-data; boundary=1408827490794
Content-Length: 213

--1408827490794
Content-Disposition: form-data; name="file"; filename="test.png"
Content-Type: image/png

PNG


IHDR

·ü]þPLTEÿâ  7
IDA×cÀ
      ÚqÅIEND®B`
--1408827490794--
Run Code Online (Sandbox Code Playgroud)

我收到错误: Error: failed [400] Missing end boundary in multipart body.

Tom*_*wel 6

修复边界

  1. 如果将边界定义为:BOUNDARY,
  2. 那么每个子部分的开头都标有: --BOUNDARY
  3. 并且消息的结尾标有: --BOUNDARY--

您的边界定义为

Content-Type: multipart/form-data; boundary=---------------------------1408816255735
Run Code Online (Sandbox Code Playgroud)

所以边界字符串是:---------------------------1408816255735,已经有28个-(如果我正确计算),所以分隔符应该是--+边界字符串,(不是"只是边界字符串").

---------------------------如果--添加或不添加前面的话,我会消除开销.

Content-Type: multipart/form-data; boundary=1408816255735
Run Code Online (Sandbox Code Playgroud)

...

--1408816255735
Content-Disposition: form-data; name="file"; filename="test.png"
Run Code Online (Sandbox Code Playgroud)

...

--1408816255735--
Run Code Online (Sandbox Code Playgroud)

"多部分体中缺少结束边界"错误

如你所说固定边界后的问题是:Missing end boundary in multipart body.

结束债券标记后,您可能还需要'\ r \n';).因为var bodyString = bodyParts.join('\r\n');没有把\ r \n放在最后一个元素之后,我想这是必需的.(我们在评论中的讨论表明,情况并非如此,所以...)

...所以我怀疑Content-Length被设置为incorectly(它应该是字节数而不是字符串中的字符数).由于内容长度不是必需的 - 也许没有它也可以尝试.(在这种情况下,这恰好是正确的猜测).

二进制数据

好的,直到现在我们修复了给定代码中的错误.正如您现在所说,多部分请求已成功解析但在尝试将发送的数据解释为PNG图像时出现服务器错误.

我不知道你是如何得到二进制数据的 - 没有代码.假设在你的循环中,partd value.data是带有图像字节的nodejs Buffer,我试试:

_.each(parts, function (value, key) {
    bodyParts.push(
        '--' + boundary,
        'Content-Disposition: form-data; name="' + key + '"; filename="' + 
                value.filename + '"',
        'Content-Transfer-Encoding: base64',
        'Content-Type: ' + value.contentType,
        '',
        value.data.toString('base64'));
});
Run Code Online (Sandbox Code Playgroud)