Node.js http 模块中设置超时的 API

超时控制主要涉及服务器端连接超时客户端请求超时两大场景

一、服务器端超时设置(http.Server 相关)

服务器端的超时主要针对客户端连接:当客户端与服务器建立 TCP 连接后,如果长时间没有数据交互(如客户端未发送请求、或请求未完成),服务器可以主动断开连接,释放资源。

1. server.setTimeout(msecs[, callback])
  • 作用:设置客户端连接的超时时间(从连接建立到数据交互的最大间隔)。
  • 参数
    • msecs:超时时间(毫秒),默认值为 5000(5 秒)。
    • callback(可选):超时事件的回调函数,等同于监听 'timeout' 事件。
  • 行为:当连接超时后,会触发服务器的 'timeout' 事件,同时底层 TCP 套接字(socket)会被标记为超时状态。
  • 注意:超时后不会自动关闭连接,需手动调用 socket.destroy() 关闭,否则连接会保持。
2. 'timeout' 事件(服务器端)
  • 触发时机:客户端连接超时(超过 setTimeout 设置的时间)时触发。
  • 参数
    • socket:超时的 TCP 套接字对象(net.Socket 实例)。
  • 用途:通常在事件回调中手动关闭超时连接,避免资源泄漏。

示例:服务器端设置连接超时

const http = require('http');

const server = http.createServer((req, res) => {
  // 模拟耗时处理(若客户端 3 秒内未发送完整请求,会触发超时)
  setTimeout(() => {
    res.end('处理完成');
  }, 4000);
});

// 设置超时时间为 3 秒(3000 毫秒)
server.setTimeout(3000, (socket) => {
  console.log('连接超时(通过 callback 处理)');
  // 手动关闭超时连接
  socket.destroy();
});

// 或通过 'timeout' 事件处理
server.on('timeout', (socket) => {
  console.log('连接超时(通过事件监听处理)');
  socket.destroy(); // 关闭连接,避免资源占用
});

server.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
});

说明

  • 若客户端在 3 秒内未完成请求(如仅建立连接但未发送数据),服务器会触发 'timeout' 事件,调用 socket.destroy() 强制关闭连接。
  • 超时时间应根据业务场景设置(如 API 服务可设 5-10 秒,文件上传可设更长时间)。

二、客户端超时设置(http.ClientRequest 相关)

客户端的超时主要针对请求过程:当客户端发送请求后,若服务器长时间未响应(无数据返回),客户端可以主动终止请求,避免无限等待。

1. req.setTimeout(msecs[, callback])
  • 作用:设置客户端请求的超时时间(从请求发送到收到响应的最大间隔)。
  • 参数
    • msecs:超时时间(毫秒),无默认值(需手动设置,否则可能无限等待)。
    • callback(可选):超时事件的回调函数,等同于监听 'timeout' 事件。
  • 行为:当请求超时后,会触发 'timeout' 事件,但不会自动终止请求,需手动调用 req.abort() 或 req.destroy() 终止。
2. 'timeout' 事件(客户端)
  • 触发时机:请求超时(超过 setTimeout 设置的时间)时触发。
  • 用途:在事件回调中终止请求,释放本地资源。

示例:客户端设置请求超时

const http = require('http');

const options = {
  hostname: 'localhost',
  port: 3000,
  path: '/slow', // 假设该接口会延迟 5 秒响应
  method: 'GET'
};

const req = http.request(options, (res) => {
  let data = '';
  res.on('data', (chunk) => { data += chunk; });
  res.on('end', () => {
    console.log('响应内容:', data);
  });
});

// 设置请求超时时间为 3 秒(若 3 秒内无响应,则触发超时)
req.setTimeout(3000, () => {
  console.log('请求超时,终止请求');
  req.abort(); // 终止请求(会触发 'abort' 事件)
});

// 处理超时后的错误
req.on('error', (err) => {
  if (err.code === 'ECONNRESET') {
    console.log('请求被主动终止(超时)');
  } else {
    console.error('请求错误:', err);
  }
});

req.end();

说明

  • 若服务器 3 秒内未返回响应,客户端触发 'timeout' 事件,调用 req.abort() 终止请求,避免无限等待。
  • 终止后会触发 'error' 事件,错误码为 ECONNRESET(连接被重置),需在事件中处理。

三、底层套接字(net.Socket)的超时补充

无论是服务器端的 socket(来自 'connection' 事件)还是客户端请求的 socket(可通过 req.socket 访问),其底层都是 net.Socket 实例,也提供超时控制:

  • socket.setTimeout(msecs[, callback]):设置套接字的超时时间(与 http.Server 或 http.ClientRequest 的超时类似,但更底层)。
  • socket.on('timeout', () => { ... }):套接字超时事件,通常无需单独设置,因为 http 模块已封装上层超时。

注意http 模块的超时 API(server.setTimeoutreq.setTimeout)本质上是对 net.Socket 超时的封装,优先使用上层 API 更符合 HTTP 场景。


四、超时 API 对比与最佳实践

场景核心 API超时触发条件处理方式
服务器端server.setTimeout()客户端连接后长时间无数据交互调用 socket.destroy() 关闭连接
客户端req.setTimeout()发送请求后长时间未收到服务器响应调用 req.abort() 终止请求

最佳实践

  1. 服务器端:根据业务设置合理超时(如普通接口 5-10 秒,大文件上传 60 秒以上),超时后必须关闭 socket
  2. 客户端:强制设置超时(如 10-30 秒),避免因网络异常导致请求永久挂起,超时后需终止请求并处理错误。
  3. 区分场景:服务器超时针对 “客户端不活跃”,客户端超时针对 “服务器无响应”,二者需分别设置。
1、服务器端超时设置(防止客户端连接长期无活动)

服务器需要限制客户端连接的最大空闲时间,避免资源浪费。

const http = require('http');

// 创建服务器
const server = http.createServer((req, res) => {
  // 模拟处理耗时请求(例如:5秒后响应)
  setTimeout(() => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('请求处理完成\n');
  }, 5000);
});

// 1. 设置服务器连接超时时间(3秒)
// 超过3秒无数据交互则触发超时
server.setTimeout(3000);

// 2. 监听超时事件,主动关闭无效连接
server.on('timeout', (socket) => {
  console.log('客户端连接超时,即将关闭连接');
  // 关闭底层TCP连接(必须手动调用,否则连接会保持)
  socket.destroy(new Error('连接超时:服务器已关闭长时间无活动的连接'));
});

// 3. 监听连接错误(如超时后关闭连接的错误)
server.on('connection', (socket) => {
  socket.on('error', (err) => {
    console.log('连接错误:', err.message);
  });
});

// 启动服务器
server.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
  console.log('连接超时设置:3秒(3000ms)');
});

测试方式
用 curl http://localhost:3000 发起请求,由于服务器处理需要 5 秒,超过 3 秒超时设置,会触发超时并关闭连接,客户端会收到错误。

2、客户端请求超时设置(防止服务器无响应)

客户端需要限制请求的最大等待时间,避免因服务器故障导致无限等待。

const http = require('http');

// 向服务器发送请求(假设服务器处理耗时较长)
const options = {
  hostname: 'localhost',
  port: 3000,
  path: '/',
  method: 'GET'
};

const req = http.request(options, (res) => {
  console.log(`收到响应,状态码:${res.statusCode}`);
  
  let data = '';
  res.on('data', (chunk) => { data += chunk; });
  res.on('end', () => {
    console.log('响应内容:', data);
  });
});

// 1. 设置客户端请求超时时间(4秒)
// 若4秒内未收到服务器响应,则触发超时
req.setTimeout(4000);

// 2. 监听超时事件,主动终止请求
req.on('timeout', () => {
  console.log('请求超时(4秒未收到响应),终止请求');
  // 终止请求(会触发后续的error事件)
  req.abort();
});

// 3. 处理请求错误(包括超时导致的错误)
req.on('error', (err) => {
  if (err.code === 'ECONNRESET') {
    console.log('请求已被主动终止(超时)');
  } else {
    console.error('请求错误:', err.message);
  }
});

// 发送请求
req.end();

测试方式
配合上面的服务器代码运行,服务器处理需要 5 秒,客户端设置 4 秒超时,会触发超时并终止请求,输出 “请求超时” 信息。

3、精细化控制:按请求类型设置不同超时

实际业务中,不同接口(如普通接口、文件上传)可能需要不同的超时时间,可在请求处理函数中动态设置。

const http = require('http');

const server = http.createServer((req, res) => {
  // 1. 按请求路径动态设置超时
  if (req.url === '/upload' && req.method === 'POST') {
    // 文件上传允许更长超时(30秒)
    req.socket.setTimeout(30000); 
    console.log('文件上传接口超时设置:30秒');
  } else {
    // 普通接口超时(5秒)
    req.socket.setTimeout(5000);
    console.log('普通接口超时设置:5秒');
  }

  // 2. 监听当前请求的超时事件
  req.socket.on('timeout', () => {
    console.log(`[${req.url}] 请求超时`);
    res.writeHead(408, { 'Content-Type': 'text/plain' }); // 408 Request Timeout
    res.end('请求超时:服务器未在规定时间内收到完整请求\n');
    req.socket.destroy(); // 关闭连接
  });

  // 模拟处理请求
  setTimeout(() => {
    res.end(`[${req.url}] 处理完成\n`);
  }, 6000); // 模拟6秒处理时间(会触发普通接口超时)
});

server.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
  console.log('测试:GET / (5秒超时),POST /upload (30秒超时)');
});

测试方式

  • 访问 http://localhost:3000(普通接口):6 秒处理时间超过 5 秒超时,会返回 408 状态码。
  • 发送 POST 请求到 http://localhost:3000/upload:6 秒处理时间未超过 30 秒超时,会正常响应。
4、HTTPS 场景的超时设置(与 HTTP 类似)

https 模块的超时 API 与 http 完全一致,只需替换模块引入即可。

const https = require('https');
const fs = require('fs');

// 证书配置(实际使用时替换为真实证书)
const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
};

// 创建HTTPS服务器,超时设置与HTTP相同
const server = https.createServer(options, (req, res) => {
  res.end('HTTPS 响应\n');
});

// 设置超时(5秒)
server.setTimeout(5000);
server.on('timeout', (socket) => {
  console.log('HTTPS连接超时');
  socket.destroy();
});

server.listen(443, () => {
  console.log('HTTPS服务器运行在 https://localhost');
});
核心总结
  1. 服务器端:通过 server.setTimeout() 或 req.socket.setTimeout() 设置超时,超时后需调用 socket.destroy() 关闭连接。
  2. 客户端:通过 req.setTimeout() 设置超时,超时后调用 req.abort() 终止请求,并在 'error' 事件中处理 ECONNRESET 错误。
  3. 灵活性:可根据请求类型(如接口、文件上传)动态调整超时时间,平衡用户体验与资源利用率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空下的DeppBing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值