从公共汽车到请求柱的管道流

我有我正在发布到一个快速端点,在下面形成标记:multipart/form-data/data/upload

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

我正在使用读取文件流,这工作正常。从那里,我想使用npm模块再次将流发送到第二个Java后端。JS 客户机/Java 服务器代码如下:busboymultipart/form-datarequest

  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 endpoint (api/data)

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

我不认为我在这里正确发送文件...但是我很难弄清楚如何从客户端的临时文件直接管道传输流到而不读取/写入。有什么想法吗?multipart/form-databusboyrequest

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}

拉哈特建议的更改

 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)

答案 1

这里的问题是,您需要手动为分段上传提供“内容长度”,因为请求(和基础表单数据)无法自行解决。因此,请求发送无效的内容长度:199(对于任何传入文件大小相同),这会破坏java多部分解析器。

有多种解决方法:

1) 使用传入请求“内容长度”

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能够在没有任何投诉的情况下解析它。

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限制

3)上传前将文件缓冲到磁盘(仅供参考)

  • express + multer - 我建议对Web服务器使用express,它使事情更容易管理,而multer是基于busboy的
  • 强大

答案 2

如果可能,请发送具有确切大小文件(字节)的自定义标头。始终可以在处理负载流之前读取标头。使用这个而不是上一个答案的内容长度标题,因为这有时不起作用(对于小文件,我猜,但我不能确保适用于大文件)。