我使用 multiparty 解析前端上传的文件,然后使用 request 上传到文件服务器。
form.on('part', function(part) {
if (part.filename) {
var formData = {
name: part.filename,
my_file: part
};
request.post({
url: 'http://service.com/upload',
formData: formData
}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
}
});
request的官方示例是将文件的 readStream , 传入 formdata。例如
var formData = {
my_file: fs.createReadStream(__dirname + '/unicycle.jpg'),
}
但是我并不想先创建临时文件,然后再获取 readStream。 由于 multiparty的 part 也是一种可读流, transform stream,它同时具有 readStream 和 writeStream 的接口,所以我想将 part 直接传入formdata。 但是遇到了下面的错误
TypeError: form-data: Invalid non-string/buffer chunk
由于文件服务器是远端的线上服务器,它的细节我并不清楚。 但是它确实能支持从文件创建的 readStream 的 formdata 的上传。 但是 part 就不行。
这里想请教一下, transform stream 和 fs.createStream 有什么不同? 有什么办法可以将 transform stream 的数据 转交给 readStream? 谢谢。
前端需要设置正确的mime。应该有这个方法
好吧, 我自己找到了答案。 使用 form-data
使用 form-data
问题中提到的 part 是一种 transform 流, 这种流一般用于对数据进行transform,也就是转化。它既可读,亦可写,实际上是当有数据输入时,才会输出。可以把它想象成一个转化数据的盒子。
requset 模块可以post form data,像这样。
var form = {
name: 'xxx',
my_file: streamObj
};
request.post({
url: 'http://service.com/upload',
formData: form
},callback);
这个form只是单纯的 js 对象,request 会将它转化为 formdata。 request 可以从 streamObj 中获取到它需要的所有信息,但是这个 stream 只支持 fs.readStream, http.response 。 对于其他 stream,需要提供文件相关的信息。
下面是原文,大概意思就是上面说的。
Form-Data can recognize and fetch all the required information from common types of streams (fs.readStream, http.response and mikeal’s request), for some other types of streams you’d need to provide “file”-related information manually:
所以,必须使用下面的方式构造 form,原始的 form-data,当然,首先你得 npm install form-data。
var form = new FormData();
form.append('fieldname', part, {
filename: part.filename,
contentType: part.headers['content-type'],
knownLength: part.byteCount
});
filename,headers,byteCount 都是 part 的自有属性。
设置 http header Transfer-Encoding: chunked
当part事件触发时,说明客户端表单中的文件部分开始上传到当前服务器了,这个时候,我们将 part 交给发送数据到文件服务器的 http request。此时,必须给这个 request 指定一个header
Transfer-Encoding: chunked
这是为什么呢? 因为,content-length 此时是不确定的,因为客户端的数据还没有上传完毕。我们必须告知文件服务器,请求的长度还不确定,你必须等我说停才能停。
这就是设置这个 header 的意义。