在multipart/form-data上传中,为每个部分设置content-length头。

19

我想使用multipart/form-data类型的POST请求上传多个文件,并且对于每个文件,我需要在服务器端知道文件大小(content-length)。

为了构建javascript中的POST请求,我使用FormData对象并将要上传的File对象附加到其中。这很好用,但是每个部分仅添加了Content-type标头,除了Content-Disposition标头外,没有添加Content-length标头,尽管此信息可以从单个File对象获取。

是否有一种方法可以在发送请求时从FormData对象设置每个部分的Content-length标头?

下面是我使用的代码,包括解决问题的工作方式。实际上,它使用angular-js发送请求,但我认为这与问题无关。

var form = new window.FormData();

form.append('additional-field-1', new Blob(['some plain text'], {type : 'text/plain'}));

for (var file in fileList) {
    var fileObj = fileList[file];
    var count = 1 + parseInt(file, null);
    form.append('file-size-' + count, new Blob([fileObj.size], {type : 'text/plain'}));
    form.append('file-' + count, fileObj);
}

$http.post(url, form, {
    transformRequest: angular.identity,
    headers: {'Content-Type': undefined}
}).success(.....

我已经为此添加了赏金,这对我来说也很痛苦。 - James
1
你能解释一下为什么你需要这个吗?通常,服务器端代码通过查找边界分隔符、解析头部等方式来计算多部分数据中每个“部分”的大小 - 剩下的就是数据。你是否因某种原因需要在解析每个“部分”的正文之前知道每个部分的大小? - sheltond
我不认为这是可能的。Angular使用本地浏览器功能来序列化和发送HTTP请求。Content-Type和Content-Disposition由浏览器设置,而不是Angular。 - Volodymyr Usarskyy
1
好的,https://tools.ietf.org/html/rfc2046 上说:“唯一具有为主体部分定义含义的标题字段是那些名称以'Content-'开头的字段。” 这意味着添加content-length标题是有效的,但似乎HTML5 FormData类不允许您这样做。该类实际上只执行多部分编码,因此您可以使用替代方法,但我在简短搜索中没有找到符合您要求的方法。 - sheltond
在我的使用中,我正在使用Angular $resource来形成请求到一个multipart/mixed表单,该表单将多个图像发布到服务器。为了了解上传所需的时间以及传输状态,现在它为每个部分使用Content-length头,整个帖子是在Java中手动生成的。我正在尝试转移到全JS解决方案,但formData似乎无法处理此类型的请求。 - James
显示剩余2条评论
1个回答

5

我认为实际上没有办法为每个表单数据元素添加自定义头。但是,您为什么不将其添加到内容分配头中,作为文件名的一部分:

data = new FormData();
data.append('additional-field-1', new Blob(['some plain text'], {type : 'text/plain'}));

for (var i = 0; i< $( '#file' )[0].files.length; i++) {
   var fileObj = $( '#file' )[0].files[i];
   data.append( '{ size : ' + fileObj.size + ' }' , $( '#file' [0].files[i], $( '#file' )[0].files[i].name );
}

我不确定你在服务器上是如何处理这个请求的,但请求应该像这样:
------WebKitFormBoundarysZxMHYOzMkqDmOvR
Content-Disposition: form-data; name="additional-field-1"; filename="blob"
Content-Type: text/plain


------WebKitFormBoundarysZxMHYOzMkqDmOvR
Content-Disposition: form-data; name="{ size : 22984 }"; filename="MatrixArithmetic.vshost.exe"
Content-Type: application/x-msdownload


------WebKitFormBoundarysZxMHYOzMkqDmOvR
Content-Disposition: form-data; name="{ size : 187 }"; filename="MatrixArithmetic.vshost.exe.config"
Content-Type: application/xml


------WebKitFormBoundarysZxMHYOzMkqDmOvR--

我遇到的问题是尝试复制一个Java开发人员将头信息硬编码到原始POST中的功能,但似乎在这里无法复制。 - James

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