【问题标题】:Why multipart is not generating close events为什么 multipart 不生成关闭事件
【发布时间】:2013-09-07 01:23:12
【问题描述】:

您好,我不会在不接触磁盘驱动器的情况下自己处理上传流。 所以,对我来说,自然选择是多方模块。

我采用了一般示例,并根据页面 https://npmjs.org/package/multiparty 的说明将 form.parse 更改为非回调请求。在这种情况下,磁盘不会被触及。

我的代码如下所示:

multiparty = require("multiparty")
http = require("http")
util = require("util")

# show a file upload form
http.createServer((req, res) ->
  if req.url is "/upload" and req.method is "POST"
    form = new multiparty.Form()

    form.on 'error', (err) ->
      console.log "Error received #{err}"

    form.on 'aborted',  ->
      console.log "Aborted"

    form.on 'part', (part) ->
      console.log "Part"

    form.on 'close', (part) ->
      console.log "close received"
      res.writeHead 200,
        "content-type": "text/plain"
      res.end "received upload:\n\n"

    form.on 'progress', (bytesReceived, bytesExpected) ->
      console.log "Received #{bytesReceived}, #{bytesExpected}"

    form.parse req
  else
    res.writeHead 200,
      "content-type": "text/html"

    res.end "<form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">" + "<input type=\"text\" name=\"title\"><br>" + "<input type=\"file\" name=\"upload\" multiple=\"multiple\"><br>" + "<input type=\"submit\" value=\"Upload\">" + "</form>"
).listen 8080 

控制台输出如下所示:

Part
Part
Received 64983, 337353
Received 130519, 337353
Aborted
Error received Error: Request aborted

没有产生close事件所以不知道什么时候读完socket。 如果我换行:

form.parse req

到:

form.parse req, (err, fields, files) ->
  res.writeHead 200,
    "content-type": "text/plain"

  res.write "received upload:\n\n"
  res.end util.inspect(
    fields: fields
    files: files
  )

然后一切都很好,关闭事件被调用。但是文件存储在磁盘上。控制台如下所示:

Part
Part
Received 65536, 337353
Received 131072, 337353
Received 196608, 337353
Received 262144, 337353
Received 327680, 337353
Received 337353, 337353
close received

知道有什么问题吗?

【问题讨论】:

  • 不,我用不同的方式重写它,以避免出现此类问题。
  • 您能否展示您如何重写它以便其他人也能找到解决方案? :)
  • @DallaRosa 我可以在下周尝试这样做。本周我面临一些最后期限,没有机会,尤其是我现在不记得它是如何工作的:)。

标签: node.js http express coffeescript


【解决方案1】:

在这种情况下,由于您没有将数据通过管道传输到文件,因此仅当所有数据都已从 req 对象中传输出来时才会发出 close,从而导致 req 在内部发出 finish 事件,触发多方close 事件。

在实践中,如果您需要close 事件,请始终将数据拉出部件,无论是到黑洞还是有意义的位置(文件或临时保存流)。 这也意味着使用close 事件来持续控制流可能非常棘手。

如果你不想对数据做任何事情,你可以像这样把它黑洞:

form.on("part", function(part) {
    out = new stream.Writable(); // require("stream") to get this native class
    out._write = function (chunk, encoding, done) {
        done(); // Don't do anything with the data
    };
    part.pipe(out);
});

令人困惑的部分是不访问part 的代码将为小文件调用close 事件,但不会在大文件上调用(我是如何遇到这个问题的)。原因是close事件与你是否从part中读取数据无关,而是与req中是否所有数据都已传输无关。

节点流一次只在它们的缓冲区之间传输几个块。因此,小文件能够将其整个缓冲区从req 传输到part,而无需填充part 的内部缓冲区。较大的文件将填满part 的缓冲区,但req 中仍有剩余数据,需要读取part 以获取req 缓冲区中剩余的数据。

这一事实也使得将close 事件用于任何有关控制流的事情变得很棘手。例如,part 仍然可以处理,但 close 将被发送,同样因为 close 不依赖于 part 完成,而是依赖于 req 为空。混乱!

【讨论】:

    【解决方案2】:

    我认为您至少需要在某处读取任何接收到的部分才能完成请求处理并触发关闭事件:

    form.on('part', function(part) {
        part.pipe(fs.createWriteStream('/dev/null'));
    });
    

    如果没有这个,我想您的请求仍在等待处理。 (请注意,有比 "> /dev/null" 更优雅、更少脚本的方式,但这只是一个示例;)

    【讨论】:

      猜你喜欢
      • 2012-11-17
      • 2018-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 2016-09-17
      • 2014-11-17
      相关资源
      最近更新 更多