node.js - request 上传文件错误
伊谢尔伦
伊谢尔伦 2017-04-17 13:06:41
0
2
905

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

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

全部回覆(2)
Peter_Zhu

好吧, 我自己找到答案了。
使用 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 的意義。

小葫芦

用pipe試試?

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板