【问题标题】:How to pipe from standard input to an http request in NodeJS?如何从标准输入管道到 NodeJS 中的 http 请求?
【发布时间】:2021-10-29 16:05:57
【问题描述】:

我有一个在端口 9090 上侦听的 http 服务器 - 像这样将请求传送到标准输出:

let server  = http.createServer((req, res) => {req.pipe(process.stdout)})
server.listen(9090)

当我像这样用 curl 发送一些东西时:

curl -XGET -T - 'http://localhost:9090' < /tmp/text-input

它有效,我在服务器终端上看到了输出

但是当我在节点中尝试以下操作时:

const http = require('http')
const nurl = new URL("http://localhost:9090")
let request = http.request(nurl)

request.on('response', (res) => {
  process.stdin.pipe(request)
})

request.end() // If I emit this, nothing happens. If I keep this, I get the below error

并尝试像这样运行它:node request.js &lt; /tmp/text-input,我收到以下错误:

node:events:368
      throw er; // Unhandled 'error' event
      ^

Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    at new NodeError (node:internal/errors:371:5)
    at write_ (node:_http_outgoing:748:11)
    at ClientRequest.write (node:_http_outgoing:707:15)
    at ClientRequest.<anonymous> (/home/tomk/workspace/js-playground/http.js:17:7)
    at ClientRequest.emit (node:events:390:28)
    at HTTPParser.parserOnIncomingClient (node:_http_client:623:27)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:128:17)
    at Socket.socketOnData (node:_http_client:487:22)
    at Socket.emit (node:events:390:28)
    at addChunk (node:internal/streams/readable:324:12)
Emitted 'error' event on ClientRequest instance at:
    at emitErrorNt (node:_http_outgoing:726:9)
    at processTicksAndRejections (node:internal/process/task_queues:84:21) {
  code: 'ERR_STREAM_WRITE_AFTER_END'
}

我想以与curl -T - 相同的方式将我的标准输入传送到http 服务器。我的请求代码有什么问题?

【问题讨论】:

    标签: node.js http


    【解决方案1】:

    简答

    要在节点中发送分块编码消息,请使用 POST 方法:

    let request = http.request(url, { method: 'POST' })
    process.stdin.pipe(request)
    

    编辑:更直接的方法

    或者,使用分块编码发送任何请求方法:

    let request = http.request(url)
    request.setHeader("transfer-encoding", "chunked")
    request.flushHeaders()
    process.stdin.pipe(request)
    

    略长(但部分)的答案

    我像 nc -l 9090 这样打开了一个监听 netcat(在普通 tcp 上监听),以查看来自 curl 的请求与我的代码有何不同,并在标头中发现了一些关键差异。

    在 curl 中,出现了标头 Transfer-Encoding: chunked,但在我的代码发出的请求中丢失了。另外,我的代码有一个标题Connection: closed

    我记录了请求对象,发现useChunkedEncodingByDefault 设置为false,考虑到nodejs http docs 的引用,这令人困惑:

    发送“Content-Length”标头将禁用默认的分块编码。

    暗示它应该是默认值。

    但是后来我在node的源中找到了this

      if (method === 'GET' ||
          method === 'HEAD' ||
          method === 'DELETE' ||
          method === 'OPTIONS' ||
          method === 'TRACE' ||
          method === 'CONNECT') {
        this.useChunkedEncodingByDefault = false;
      } else {
        this.useChunkedEncodingByDefault = true;
      }
    

    编辑

    无论如何要发送分块编码,我(最终)发现我需要明确添加 Transfer-Encoding: Chunked 标头:

    request.setHeader("transfer-encoding", "chunked")
    # and then
    request.flushHeaders()
    

    因此,总而言之,节点不允许发送默认发送带有分块编码的 GET 请求,但 curl 可以。奇怪,不幸的是没有记录(据我所知),但重要的是我让它工作

    【讨论】:

      猜你喜欢
      • 2020-05-11
      • 2016-07-24
      • 1970-01-01
      • 2014-02-22
      • 2020-02-12
      • 2020-04-01
      • 1970-01-01
      • 2020-04-06
      • 1970-01-01
      相关资源
      最近更新 更多