request 上传文件。使用 transform stream 作为 form data 中的文件数据。出现 typeErr 错误
发布于 7 年前 作者 dmoneh 5336 次浏览 最后一次编辑是 6 年前 来自 问答

我使用 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? 谢谢。

2 回复

前端需要设置正确的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 的意义。

回到顶部