[expressjs/express]undefined: 如果在 express 中使用 http.request,则 undefined 会添加到 http 请求标头中

2024-07-04 894 views
3

如果我在我的 express 端点实现中使用 node http(s) 库来查询外部服务,它会在我的标头中添加大量 'undefined: undefined' 尾随垃圾。如果我在 express 之外执行以下代码:

let resp = ''
https.get({
  protocol: 'https:',
  host: 'my-favorite-app-behind-cloudfront',
  path: '/my-favorite-endpoint',
  headers: {
    'Authorization': 'Bearer some-token',
    'x-my-favorite-header': 'my-value'
  }
}, (res) => {
  res.setEncoding('utf8')
  res.on('data', (chunk) => {
    resp += chunk
  })
  res.on('end', () => {
    console.log(res.req._header);
  })
}
).on('error', (err) => {
  console.log(err)
})

我得到了预期的输出:

GET /products HTTP/1.1
Authorization: Bearer some-token
x-my-favorite-header: my-value
Host: my-favorite-app-behind-cloudfront
Connection: close

但是,当我在快速端点处理程序中执行相同操作时,我得到了以下信息:

GET /products HTTP/1.1
Authorization: Bearer some-token
x-my-favorite-header: my-value
Host: my-favorite-app-behind-cloudfront
undefined: undefined
[...ditto 42 times...]
undefined: undefined
Connection: close

Express.js 版本:4.15.5 和 4.16.x Node.js 版本:8.9.1 操作系统:Darwin 内核版本 16.7.0:2017 年 10 月 4 日星期三 00:17:00 PDT;root:xnu-3789.71.6~1/RELEASE_X86_64

回答

9

奇怪,我之前没见过这种情况,也不知道从哪里开始查找。您能否提供一个 Express 应用程序示例,该应用程序发出的请求可重现此问题?我很快尝试了一下,但似乎没有成功。

5

我会开始查看类似https://github.com/expressjs/express/blob/b97faff6e2aa4d34d79485fe4331cb0eec13ad57/lib/request.js 应用程序的内容,它相当简单,端点本身的初始化方式如下: index.js

const config = require('config')
const logger = require('@whatever/bootstrap').getLogger()
const app = require('./src/app')
app.listen(config.app.port, config.app.host, () => {
  logger.info(`Server listening on ${config.app.host}:${config.app.port}`)
})

app.js

const express = require('express')
const timeout = require('connect-timeout')
const bodyParser = require('body-parser')
const logger = require('@whatver/bootstrap').getLogger()
const {json} = require('./utils')
const cors = require('cors')
const path = require('path')

const DIST_DIR = path.join(__dirname, '../dist')

const app = express()
app.use(cors())
app.use(timeout(120000))
app.use(bodyParser.json({ limit: '5mb', type: '*/*' }))
app.use((req, res, next) => {
  logger.info(`${req.method} ${req.path} headers: ${json(req.headers)} body: ${json(req.body)}`)
  next()
})
app.use('/', require('./routes'))
app.use(express.static(DIST_DIR))
module.exports = app

routes/index.js

const express = require('express')
const router = express.Router()
....
router.use('/my-endpoints', require('./my-endpoints'))
module.exports = router

my-endpoints.js

const express = require('express')
const router = express.Router()
const https = require('https')
router.get('/products', async (req, res) => {
//basic param handling and then something like:
let resp = ''
https.get({
  protocol: 'https:',
  host: 'my-favorite-app-behind-cloudfront',
  path: '/my-favorite-endpoint',
  headers: {
    'Authorization': 'Bearer some-token',
    'x-my-favorite-header': 'my-value'
  }
}, (res) => {
  res.setEncoding('utf8')
  res.on('data', (chunk) => {
    resp += chunk
  })
  res.on('end', () => {
    console.log(res.req._header);
  })
}
).on('error', (err) => {
  console.log(err)
})
}
module.exports = router
2

我可能对你所说的未定义标头感到困惑。它们是在 http.request 发出的请求中,还是在对 http.request 的响应中,还是在对 http 服务器本身的请求的响应中?

也许您能提供一些关于如何运行代码以及在哪里查看问题的分步说明?此外,如果您混合了许多其他模块,请查看是否可以删除它们以简化示例,或者提供您安装的每个模块的确切版本,以便我可以获得 sams 环境。

我弄乱了你的例子,但还是什么也没发现。不过,我不确定我是否找对了地方,或者我对上面的代码进行了修改,以便它能够运行,从而解决了这个问题。

6

http.request 发出的请求中包含额外的标头,即发送到服务器的 http 流包含额外的意外undefined: undefined\n\r行,但前提是上述代码是在 express 端点处理程序的上下文中执行的。我将尝试提供尽可能简短的要点来重现该问题。

8

谢谢。我还在玩,还没有看到它。为了确保万无一失,我还使用了 Node.js 8.9.1。Express 不会改变任何全局内容,也不会触及与发出出站请求有关的任何内容,所以我甚至想不出从哪里开始查找潜在原因。这是我正在使用的独立代码。它能为您重现吗?也许用这个作为构建点会有助于制作一个最小示例?

const express = require('express') // npm i express@4.16.2
const get = require('http').get
const net = require('net')
const app = express()

net.createServer((socket) => {
  socket.setEncoding('utf8')
  socket.on('data', (chunk) => {
    console.log(chunk.replace(/^/gm, '> '))
  })
}).listen(3001)

app.get('/', (req, res) => {
  get({
    protocol: 'http:',
    host: 'localhost',
    port: 3001,
    path: '/foo',
    headers: {
      'Authorization': 'Bearer some-token',
      'x-my-favorite-header': 'my-value'
    }
  }, (response) => {
    let body = ''
    response.setEncoding('utf8')
    response.on('data', (chunk) => { body += chunk })
    response.on('end', () => {
      console.log(response.req._header)
      console.log(body)
    })
  })
})

app.listen(3000, () => {
  get('http://localhost:3000/')
})

我得到的输出:

> GET /foo HTTP/1.1
> Authorization: Bearer some-token
> x-my-favorite-header: my-value
> Host: localhost:3001
> Connection: close
> 
> 

此输出是在 http.get 出站套接字上接收到的内容。

6

好的,所以我找到了根本原因,这似乎与表达无关,尽管无论如何有点奇怪:

const express = require('express')
const https = require('https')
const promisifyAll = require('util-promisifyall')
const redis = require('redis')

promisifyAll(redis.Multi.prototype) // that thing breaks it all

const app = express()
const google = express.Router()
google.get('/whatever', (req, res) => {
  https.get({
    protocol: 'https:',
    host: 'google.com'
  }, (remoteRes) => {
    remoteRes.on('data', () => {})
    remoteRes.on('end', () => {
      const headersSent = remoteRes.req._header
      console.log(headersSent) // lots of undefined:undefined
      res.status(200).send(headersSent)
    })
  }
  ).on('error', (err) => {
    res.status(500).send(err)
  })
})
app.use('/', google)
app.listen(8666, '0.0.0.0')
6

嗨 @mnezh 谢谢你追踪到这个问题!难怪我一直没能重现这个问题,因为之前的代码中没有 promisify 这个东西,哈哈。