在 Node.js 中使用 HTTP Agent 实现 keep-alive

不带 Keep-Alive 的请求

我们都知道,浏览器中多个 HTTP 请求是可以通过请求头 connection: keep-alive; 来复用 TCP 连接的,但是在 Node.js 中怎么实现呢?

比如,下面是一段简单的发起请求的代码:

js 复制代码
// server.js
const http = require('http')

http
  .createServer((req, res) => {
    res.writeHead(200)
    res.end('Hello World')
  })
  .listen(3000)

// client.js
const http = require('http')

function request() {
  http
    .request(
      {
        host: 'localhost',
        port: 3000,
        pathname: '/',
      },
      (res) => {
        let buffer = []
        res.on('data', (chunk) => {
          buffer.push(chunk)
        })
        res.on('end', () => {
          console.log(buffer.toString())
        })
      }
    )
    .end()
}

request()

setTimeout(() => {
  request()
}, 1000)

当我们用 wireshard 抓包分析师,我们可以两次请求的 client 端口是不同的,并且有两个"三次握手"的过程:

使用 http.Agent 发送带有 Keep-Alive 的请求

现在,让我们使用 http.Agent 来实现 keep-alive 请求,我们只需要加少量的代码:

js 复制代码
const agent = new http.Agent({
  keepAlive: true,
})

function request() {
  http
    .request(
      {
        agent,
        host: 'localhost',
        port: 3000,
        pathname: '/',
      },
      () => {
        // ...
      }
    )
    .end()
}

但是,wireshark 中的结果其实不会发生变化!实际上,我们需要指定 agent 的 maxSockets 参数:

js 复制代码
const agent = new http.Agent({
  keepAlive: true,
  maxSockets: 1,
})

为什么呢?因为 maxSockets 表示每个 host 所能建立的最大 TCP 连接数。其默认值是 Infinity。如果我们不指定它的值,那每个 HTTP 请求都会建立一个 TCP 连接。

接下来,我们修改一下代码:

js 复制代码
setTimeout(() => {
  request()
}, 10000) // 1000 -> 10000

wireshark 抓包显示:

keep-alive 又不生效了!并且我们可以看到服务端 5s 左右后发送了一个 FIN 的包。难道有什么参数可以控制 keep-alive 的超时时间么?确实,也就是 keepAliveTimeout,我们把它设置为 10s:

js 复制代码
const http = require('http')

const server = http
  .createServer((req, res) => {
    res.writeHead(200)
    res.end('Hello World')
  })
  .listen(3000)

server.keepAliveTimeout = 10000

现在 keep-alive 又可以工作了。

求关注公众号"前端游"

相关推荐
Json____13 小时前
用 FastAPI + Vue3 打造一套完整的在线考试系统:从组卷到阅卷的业务闭环实践
后端·node.js·fastapi·it学习·wwwoop.com
Dumbness1 天前
写 MCP 服务器踩的坑:stdout 是协议通道,一行不带换行的日志就能让客户端超时
node.js·mcp
flash俊杰1 天前
ContentPart 联合类型实战:不碰存量消息,怎么给 ChatMessage 加图片
node.js
Json____1 天前
用 Node.js + Vue3 打造一个家居装修 AI 智能咨询助手
node.js·agent·网站开发·智能体·wwwoop.com
幸运小圣1 天前
fs 模块完全指南:文件读写、移动删除与文件夹操作(新手友好)【Node.js】
node.js·编辑器·vim
Dumbness2 天前
不发 npm 也能 npx:用 github: 协议分发一个零依赖 CLI
node.js
Patrick_Wilson2 天前
npm 的 bin 如何接到 npm run 与 npx
npm·node.js·前端工程化
Patrick_Wilson2 天前
import 之后发生了什么:package.json、解析与安装产物
npm·node.js·前端工程化
Patrick_Wilson2 天前
npm 里 SemVer 和 dist-tag 如何决定装哪一版
npm·node.js·前端工程化
Dumbness3 天前
Node 22 下 node --test test/ 报 MODULE_NOT_FOUND:内置测试运行器的文件匹配规则
node.js·测试