【问题标题】:Why does the request pipe includes the headers in this code?为什么请求管道在此代码中包含标头?
【发布时间】:2021-10-09 16:18:59
【问题描述】:

我有一个关于 http 服务器和管道请求的奇怪情况。

根据我过去的经验,当将 http 服务器的请求对象通过管道传输到某种可写流时,它不包括标头,仅包括有效负载。

然而,今天我写了一些非常简单的代码,出于某种原因,我花了过去 2 个小时试图弄清楚为什么它将标题写入文件(超级混乱!)

这是我的代码:

server = http.createServer((req, res) => {
  f = '/tmp/dest'
  console.log(`writing to ${f}`)
  s = fs.createWriteStream(f)
  req.pipe(s)
  req.on('end', () => {
    res.end("done")
  })
})

server.listen(port)

我使用以下curl 命令对此进行测试:

curl -XPOST  -F 'data=@test.txt' localhost:8080

这就是我在阅读 /tmp/dest 时得到的:

--------------------------993d19e02b7578ff
Content-Disposition: form-data; name="data"; filename="test.txt"
Content-Type: text/plain

hello - this is some text


--------------------------993d19e02b7578ff--

为什么我会在这里看到标题?我希望它只写有效载荷

我大约一年前写了一个代码,它直接流式传输到一个没有标题的文件,我不明白有什么不同,但是这个成功了:

imageRouter.post('/upload', async(req, res) => {
  if(!req.is("image/*")) {
    let errorMessage = `the /upload destination was hit, but content-type is ${req.get("Content-Type")}`;
    console.log(errorMessage);
    res.status(415).send(errorMessage);
    return;
  }

  let imageType = req.get("Content-Type").split('/')[1];
  let [ err, writeStream ] = await getWritableStream({ suffix: imageType });
  if (err) {
    console.log("error while trying to write", err);
    return res.status(500).end();
  }

  let imageName = writeStream.getID();
  req.on('end', () => {
    req.unpipe();
    writeStream.close();
    res.json({
      imageRelativeLink: `/images/${imageName}`,
      imageFullLink: `${self_hostname}/images/${imageName}`
    });
  });
  req.pipe(writeStream);
});

有什么不同?为什么我一年前的代码(最后一个块)在没有表单数据/标题的情况下写入?结果文件只是一个图像,没有文本,但这次(第一个块)在结果文件中显示了 http 标头

【问题讨论】:

  • 你看到的是http协议格式的纯内容。这是应该的,这是根据http specification的消息。
  • 那我怎样才能只管payload呢?
  • 另外,这个答案也是一样的,只有有效载荷应该通过管道传输:stackoverflow.com/a/29199616/1463751(除非我缺少某些东西)
  • 不修改源流是不能直接做的。或者,您可以侦听请求事件(例如on(‘request’, fb))并仅提取那里的主体并将其写入您的输出流。
  • 我已经在我过去编写的代码中直接做到了 - 我只是不明白现在有什么不同。我将编辑我的问题以包含我过去编写的没有标题的流式代码

标签: node.js http-streaming


【解决方案1】:

尝试使用 on('data') 并引用 req.data 来提取内容,而不是使用管道。这将允许 http 库处理 HTTP 正文格式并为您处理“标题”(实际上是:表单部分描述符)。

Node Streaming Consumer API

    server = http.createServer((req, res) => {
      f = '/tmp/dest'
      console.log(`writing to ${f}`)
      s = fs.createWriteStream(f)
      req.on('data', chunk) => {
          s.write(chunk);
      }
      req.on('end', () => {
        s.close();
        res.end("done")
      })

})

server.listen(port)

【讨论】:

  • 谢谢,但它仍然会写入表单部分描述符...
  • 这也没有任何流控制(当s.write()返回流已满时)。
  • 如果使用 express http,是否告知 express 期望编码数据?比如:app.use
【解决方案2】:

事实证明,我的理解有误,因此我的问题也有误。

我认为是标头,实际上是 http 多部分规范。这就是 curl 在使用此语法时上传文件的方式。

我真正需要的是将使用 curl 测试代码的方式更改为以下之一:

cat /path/to/test/file | curl -T - localhost:8080
# or
curl -T - localhost:8080 < /path/to/test/file
# or
curl -T /path-/to/test/file localhost:8080 < /path/to/test/file

使用-T(或--upload-file)标志,curl 上传文件(或标准输入)而不用 http 形式包装。

【讨论】:

    猜你喜欢
    • 2021-08-28
    • 1970-01-01
    • 2017-02-24
    • 2019-09-17
    • 1970-01-01
    • 2020-04-07
    • 2012-11-07
    • 2013-10-27
    • 2018-11-11
    相关资源
    最近更新 更多