2016-04-24 56 views
9

我有multipart/form-data,我發佈一個Express端點/data/upload,下面的表格標記:管道流請求後

form(enctype="multipart/form-data", action="/data/upload", method="post") 
    input(type="file", name="data") 

我使用busboy讀取文件流,這是工作的罰款。從那裏,我想要使用request npm模塊將流再次作爲multipart/form-data發送到第二個Java後端。 JS客戶端/服務器的Java代碼如下:

req.busboy.on('file', function (fieldName, fileStream, fileName, encoding, mimeType) { 

    var reqBody = { 
     url: server.baseURL + 'api/data', 
     headers: { 
     'Connection': 'keep-alive', 
     'Content-Type': 'multipart/form-data' 
     }, 
     formData: { 
     file: fileStream 
     } 
    }; 

    request.post(reqBody, function (err, r, body) { 
     // Do rendering stuff, handle callback 
    }); 
}); 

Java的端點(API /數據)

@POST 
@Consumes(MediaType.MULTIPART_FORM_DATA) 
public void addData(FormDataMultiPart formDataMultiPart) { 
    // Handle multipart data here  
} 

我不認爲我正確地發送文件作爲multipart/form-data這裏......但我很難搞清楚如何在不從客戶端的臨時文件讀取/寫入的情況下將流從busboy直接流到request。有任何想法嗎?

Java堆棧跟蹤:

Apr 27, 2016 5:07:12 PM org.glassfish.jersey.filter.LoggingFilter log 
INFO: 3 * Server has received a request on thread qtp1631904921-24 
3 > POST http://localhost:8080/api/data 
3 > Connection: keep-alive 
3 > Content-Length: 199 
3 > Content-Type: multipart/form-data; boundary=--------------------------331473417509479560313628 
3 > Host: localhost:8080 

Apr 27, 2016 5:07:12 PM org.glassfish.jersey.filter.LoggingFilter log 
INFO: 3 * Server responded with a response on thread qtp1631904921-24 
3 < 400 

17:07:13.003 [qtp1631904921-24] WARN org.eclipse.jetty.http.HttpParser parseNext - bad HTTP parsed: 400 No URI for [email protected]{r=1,c=false,a=IDLE,uri=null} 

拉哈特推薦的變化

31  var reqBody = { 
32  url: server.baseURL + 'data', 
33  headers: { 
34   'Connection': 'keep-alive', 
35   'Content-Type': 'multipart/form-data' 
36  } 
37  }; 
38 
39  req.pipe(req.busboy.pipe(request.post(reqBody))); 

投擲了錯誤:

Error: Cannot pipe. Not readable. 
    at Busboy.Writable.pipe (_stream_writable.js:154:22) 
+0

您正在重新定義'req'。這是打算嗎? –

+0

這是一個很差的變量名稱選擇,但它不是問題。我會在上面的文章中更改它。 –

+0

你有沒有研究過你的'busboy'管道到你的java端點? –

回答

11

此處的問題是,您需要手動爲分段上傳提供「內容長度」,因爲request(和底層的form-data)無法自行計算出來。 因此請求發送無效的Content-Length:199(對於任何傳入文件大小都是相同的),這會中斷java multipart解析器。

有多種變通方法:

1)使用輸入的請求「的Content-Length」

request.post({ 
    url: server.baseURL + 'api/data', 
    formData: { 
    file: { 
     value: fileStream, 
     options: { 
     knownLength: req.headers['content-length'] 
     } 
    } 
    } 
}, function (err, r, body) { 
    // Do rendering stuff, handle callback 
}) 

這將雖然產生比特不正確請求,因爲進入的長度包括其他上傳域和邊界,但busboy的是能夠解析它的w/o任何投訴

2)等待,直到文件完全由節點應用緩衝然後將其發送到Java

var concat = require('concat-stream') 
req.busboy.on('file', function (fieldName, fileStream, fileName, encoding, mimeType) { 
    fileStream.pipe(concat(function (fileBuffer) { 
    request.post({ 
     url: server.baseURL + 'api/data', 
     formData: { 
     file: fileBuffer 
     } 
    }, function (err, r, body) { 
     // Do rendering stuff, handle callback 
    }) 
    })) 
}) 

這會增加應用程序的內存消耗,所以你必須要小心,並考慮使用busboy limits

3)緩衝到磁盤文件上傳(僅供參考)

  • express + multer前 - 我推薦使用express for webservers,它使事情更易於管理,並且multer基於busboy
  • formidable
+0

剛剛嘗試過它似乎工作。非常感謝你花時間寫這篇文章。我會盡快給予獎賞。 –

+0

不客氣!另一個可能對您的案例有用的lib(node-java集成) - 是https://github.com/nodejitsu/node-http-proxy直接向java代理一些請求,另外我建議看看https://github.com/visionmedia/superagent作爲'請求'的替代品 - 它有更清晰的語法,可以在瀏覽器和後端運行。 –

+0

在我的測試中,2仍然不適用於某些小文件。請考慮發送一個自定義標題,其中包含確切的文件大小,可以在流式啓動之前始終讀取。 – felipeaf

0

如果可能,發送一個自定義標題,大小確切的文件(字節)。標題總是可以在處理有效載荷流之前被讀取。使用它而不是以前的答案的內容長度標題,因爲這有時不起作用(我猜小文件,但我不能確保它適用於大文件)。