【问题标题】:Piping stream from busboy to request post从 busboy 管道流到请求帖子
【发布时间】:2016-08-18 04:08:33
【问题描述】:

我有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 客户端/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 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)

【问题讨论】:

  • 您正在重新定义req。这是故意的吗?
  • 变量名的选择很差,但不成问题。我会在上面的帖子中更改它。
  • 您是否考虑过通过管道将您的 busboy 连接到您的 java 端点?
  • 您有代码 sn-p 或文档链接吗?谢谢--
  • 请添加java异常的堆栈跟踪

标签: javascript java node.js express multipartform-data


【解决方案1】:

这里的问题是您需要手动为分段上传提供“Content-Length”,因为request(和底层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 能够解析它而没有任何投诉

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

【讨论】:

  • 刚刚尝试过 - 似乎有效。非常感谢您花时间写这篇文章。我会尽快奖励赏金。
  • 不客气!另一个可能对您的情况有用的库(节点 - java 集成) - 是 github.com/nodejitsu/node-http-proxy 直接将一些请求代理到 java,另外我建议看一下 github.com/visionmedia/superagent 作为“请求”的替代品 - 它语法更清晰,可以在浏览器和后端运行。
  • 在我的测试中 2 仍然不适用于一些小文件。考虑发送具有精确文件大小的自定义标头,始终可以在流开始之前读取。
【解决方案2】:

如果可能,请发送具有精确文件大小(字节)的自定义标头。始终可以在处理有效负载流之前读取标头。使用它而不是先前答案的 content-length 标头,因为这有时不起作用(我猜是小文件,但我不能确保它适用于大文件)。

【讨论】:

    【解决方案3】:

    为了阿法纳西·库拉金的回答

    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'] 更改为实际文件大小,通常标题中的内容长度大于文件大小。我因为内容长度而感到痛苦,并且在使用文件大小后,一切正常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多