2016-04-24 8 views
9

Ich habe multipart/form-data, die ich /data/upload, Form Markup unter einem ausdrücklichen Endpunkt bin Entsendung:Piping Strom von busboy zu beantragen Post

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

ich busboy bin mit dem Datei-Stream zu lesen, was in Ordnung arbeitet. Von dort möchte ich den Strom wieder als multipart/form-data zu einem zweiten Java-Backend senden, mit dem request Npm-Modul. JS Client/Java-Server-Code unten:

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-Endpunkt (api/Daten)

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

Ich glaube nicht, daß ich die Datei korrekt als multipart/form-data Senden hier ... aber Ich habe eine harte Zeit herauszufinden, wie im Wesentlichen der Stream von busboy direkt zu request ohne Lesen/Schreiben von einer temporären Datei auf der Client-Seite. Irgendwelche Ideen?

Java-Stack-Trace:

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} 

Rahat empfohlenen Änderung:

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))); 

Threw Fehler:

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

Sie definieren 'req' neu. Ist das beabsichtigt? –

+0

Es ist eine schlechte Wahl des Variablennamens, aber es ist kein Problem. Ich werde es in dem obigen Post ändern. –

+0

Haben Sie schon einmal versucht, Ihren 'Busboy' an Ihren Java-Endpunkt anzuschließen? –

Antwort

11

Das Problem hier ist, dass Sie "Content-Length" für den mehrteiligen Upload manuell angeben müssen, da request (und zugrunde liegenden form-data) es nicht selbst herausfinden können. Also Anfrage sendet ungültige Content-Length: 199 (das gleiche für jede eingehende Dateigröße), die den Java-Multipart-Parser bricht.

Es gibt mehrere Lösungen:

1) Verwenden Sie eingehende Anfrage '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 
}) 

Dies wird allerdings ein wenig falsch Anforderung erzeugen, weil eingehende Länge andere Upload-Felder und Grenzen beinhaltet, ist aber busboy konnte es w parsen/o Beschwerden

2) Warten, bis die Datei vollständig durch den Knoten app gepuffert wird dann

senden 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 
    }) 
    })) 
}) 

Dieser App Speicherverbrauch erhöhen, so dass Sie vorsichtig sein mußten und betrachten busboy limits

3) Puffer auf der Festplatte mit der Datei vor (nur für die Referenz Upload)

  • express + multer - I empfehle die Verwendung von Express für Webserver, es macht die Dinge leichter zu handhaben, und Multer basiert auf dem Busboy
+0

Probieren Sie es einfach - scheint zu funktionieren. Vielen Dank, dass Sie sich die Zeit genommen haben, dies aufzuschreiben. Ich werde Kopfgeld geben, sobald es mich lässt. –

+0

Gern geschehen! Eine weitere Lib, die für Ihren Fall nützlich sein könnte (node ​​- java integration) - ist https://github.com/nodejitsu/node-http-proxy, um einige Anfragen direkt an Java zu stellen, und ich schlage vor, einen Blick darauf zu werfen https://github.com/visionmedia/superagent als Ersatz für 'request' - es hat eine klarere Syntax und kann sowohl im Browser als auch im Backend laufen. –

+0

In meinen Tests funktioniert 2 immer noch nicht für einige kleine Dateien. Ziehen Sie in Erwägung, einen benutzerdefinierten Header mit genauer Dateigröße zu senden, der vor dem Start des Streams immer gelesen werden kann. – felipeaf

0

Wenn möglich, senden Sie einen benutzerdefinierten Header mit genau der Dateigröße (Bytes). Der Header kann immer vor dem Handle-Payload-Stream gelesen werden. Verwenden Sie diese anstelle der Inhaltslänge Header der vorherigen Antwort, weil das manchmal nicht funktioniert (mit kleinen Dateien, ich denke, aber ich kann nicht sicherstellen, dass mit großen Dateien funktioniert).