从服务生到请求的管道流 post
Piping stream from busboy to request post
我有 multipart/form-data
我要发布到一个快速端点 /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 client/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/data)
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public void addData(FormDataMultiPart formDataMultiPart) {
// Handle multipart data here
}
我认为我没有像 multipart/form-data
一样正确地发送文件...但是我很难弄清楚如何从根本上直接从 busboy
传输流从客户端的临时文件到 request
而没有 reading/writing。有什么想法吗?
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 HttpChannelOverHttp@425137da{r=1,c=false,a=IDLE,uri=null}
Rahat 的推荐更改:
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)
这里的问题是分片上传需要手动提供'Content-Length',因为request
(and underlying form-data
)自己搞不定。
因此请求发送无效的 Content-Length: 199(对于任何传入的文件大小都相同),这会破坏 java 多部分解析器。
有多种解决方法:
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,它使事情更易于管理,并且 multer 基于 busboy
- formidable
如果可能,请发送自定义 header 文件大小(字节)。 header 始终可以在处理负载流之前读取。使用它而不是以前答案的 content-length header,因为这有时不起作用(我猜是小文件,但我不能确保它适用于大文件)。
求 Afanasii Kurakin 的回答
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
})
您应该将 req.headers['content-length']
更改为实际文件大小,通常 header 中的 content-length 大于文件大小。我因为 content-length 而感到痛苦,在使用文件大小后,一切都完美无缺。
我有 multipart/form-data
我要发布到一个快速端点 /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 client/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/data)
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public void addData(FormDataMultiPart formDataMultiPart) {
// Handle multipart data here
}
我认为我没有像 multipart/form-data
一样正确地发送文件...但是我很难弄清楚如何从根本上直接从 busboy
传输流从客户端的临时文件到 request
而没有 reading/writing。有什么想法吗?
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 HttpChannelOverHttp@425137da{r=1,c=false,a=IDLE,uri=null}
Rahat 的推荐更改:
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)
这里的问题是分片上传需要手动提供'Content-Length',因为request
(and underlying form-data
)自己搞不定。
因此请求发送无效的 Content-Length: 199(对于任何传入的文件大小都相同),这会破坏 java 多部分解析器。
有多种解决方法:
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,它使事情更易于管理,并且 multer 基于 busboy
- formidable
如果可能,请发送自定义 header 文件大小(字节)。 header 始终可以在处理负载流之前读取。使用它而不是以前答案的 content-length header,因为这有时不起作用(我猜是小文件,但我不能确保它适用于大文件)。
求 Afanasii Kurakin 的回答
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
})
您应该将 req.headers['content-length']
更改为实际文件大小,通常 header 中的 content-length 大于文件大小。我因为 content-length 而感到痛苦,在使用文件大小后,一切都完美无缺。