You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用server.close()后未处理HTTP请求的相关技术咨询

Node.js服务器关闭后HTTP请求残留问题解答

问题场景

我搭建了一个原生Node.js服务器,按下ctrl-c后,会看到"Server is closed"日志,随后出现命令行提示符,但之后仍会有日志显示还在发起API调用。

在exit()中(server.close()之前)调用clearInterval(anInterval)后,服务器关闭后仍运行定时器的问题已解决,但根据Node.js官方文档说明:

关闭所有未发送请求或等待响应的服务器连接。

我推测server.close()不会自动终止HTTP请求,因此有以下疑问:

  1. 当计算机/Node不再追踪变量someVar时,HTTP响应信息会如何处理?
  2. 不专门终止发起HTTP请求并等待响应的线程会有什么后果?
  3. 取消HTTP请求的最佳实践是什么?
  4. 具体实现是通知API服务器停止发送响应,还是仅让Node不再接收新信息?

服务器代码

let someVar // to be set to a Promise

const getData = url => {
  return new Promise((resolve, reject) => {
    https.get(
      url,
      { headers: { ...COMMON_REQUEST_HEADERS, 'X-Request-Time': '' + Date.now() } },
      res => {
        if (res.statusCode === 401) return reject(new RequestError(INVALID_KEY, res))
        if (res.statusCode !== 200) return reject(new RequestError(BAD_REQUEST, res))

        let json = ''
        res.on('data', chunk => json += chunk)
        res.on('end', () => {
          try {
            resolve(JSON.parse(json).data)
          } catch (error) {
            return reject(new RequestError(INVALID_RESPONSE, res, json))
          }
        })
      }
    ).on('error', error => reject(new RequestError(FAILED, error)))
  })
}
const aCallback = () => {
  console.log('making api call')
  someVar = getData('someApiEndpoint')
    .then(data => { ... })
}
const main = () => {
  const server = http.createServer(handleRequest)
  anInterval = setInterval(aCallback, SOME_LENGTH_OF_TIME)

  const exit = () => {
    server.close(() => process.exit())
    log('Server is closed')
  }

  process.on('SIGINT', exit)
  process.on('SIGTERM', exit)

  process.on('uncaughtException', (err, origin) => {
    log(`Process caught unhandled exception ${err} ${origin}`, 'ERROR')
  })
}
main()

问题解答

1. 当计算机/Node不再追踪变量someVar时,HTTP响应信息会如何处理?

Node.js的HTTP请求基于TCP连接,只要TCP连接未断开,即便你不再持有someVar这个Promise的引用,事件循环仍会监听该连接的响应数据。如果响应返回时,Promise的回调(then/catch)还因闭包存在于内存中,回调依然会执行;若回调已被垃圾回收,响应数据会被内核接收后丢弃,但TCP连接可能会按Keep-Alive规则保持一段时间,直到超时关闭。

2. 不专门终止发起HTTP请求并等待响应的线程会有什么后果?

Node.js是单线程事件循环模型,不存在专门的请求线程——所有请求都在事件循环中处理。不终止未完成的HTTP请求,会占用事件循环资源,可能导致进程无法正常退出(除非强制调用process.exit())。此外,挂起的TCP连接会占用系统文件描述符,数量过多会导致新请求无法建立;同时API服务器会继续发送响应,浪费网络带宽和服务器资源。

3. 取消HTTP请求的最佳实践是什么?

  • 调用请求对象的destroy()方法:https.get()返回的客户端请求对象调用destroy()可立即终止TCP连接,触发请求的error事件,对应的Promise会被reject。
  • 维护未完成请求列表:用数组追踪所有正在进行的请求对象,在退出逻辑中遍历数组逐个调用destroy()。
  • 使用AbortController(Node.js v15+支持):通过信号取消请求,符合现代异步API设计,还能同时取消多个关联请求。

示例实现(基于destroy()):

// 修改getData函数,返回请求对象和Promise
const getData = url => {
  const promise = new Promise((resolve, reject) => {
    const req = https.get(
      url,
      { headers: { ...COMMON_REQUEST_HEADERS, 'X-Request-Time': '' + Date.now() } },
      res => {
        if (res.statusCode === 401) return reject(new RequestError(INVALID_KEY, res))
        if (res.statusCode !== 200) return reject(new RequestError(BAD_REQUEST, res))

        let json = ''
        res.on('data', chunk => json += chunk)
        res.on('end', () => {
          try {
            resolve(JSON.parse(json).data)
          } catch (error) {
            return reject(new RequestError(INVALID_RESPONSE, res, json))
          }
        })
      }
    ).on('error', error => reject(new RequestError(FAILED, error)))
    // 将req对象暴露出去
    req.promise = promise
    return req
  })
}

// 维护请求列表
const pendingRequests = []

const aCallback = () => {
  console.log('making api call')
  const req = getData('someApiEndpoint')
  pendingRequests.push(req)
  someVar = req.promise
    .then(data => { ... })
    .finally(() => {
      // 请求完成后从列表移除
      const index = pendingRequests.indexOf(req)
      if (index !== -1) pendingRequests.splice(index, 1)
    })
}

// 更新exit函数
const exit = () => {
  clearInterval(anInterval)
  // 取消所有未完成的请求
  pendingRequests.forEach(req => req.destroy())
  server.close(() => process.exit())
  log('Server is closed')
}

4. 具体实现是通知API服务器停止发送响应,还是仅让Node不再接收新信息?

  • 主动调用destroy()或通过AbortController取消请求时,Node.js会发送TCP FIN包关闭连接。API服务器收到FIN包后,会知晓客户端不再接收数据,通常会停止发送剩余响应(若还在发送中),并关闭自身侧的连接。
  • 若仅丢弃Promise引用而不主动取消,Node.js不会通知API服务器,服务器会继续发送完整响应,直到数据全部发送完毕,之后连接会按Keep-Alive规则关闭或直接断开。

内容的提问来源于stack exchange,提问作者Aaron Parisi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 06:10:36