题目
设计一个中间件系统实现请求超时控制
信息
- 类型:问答
- 难度:⭐⭐
考点
中间件原理,异步流程控制,错误处理
快速回答
实现请求超时控制的核心要点:
- 使用中间件链式调用机制拦截请求
- 通过
setTimeout和clearTimeout控制超时 - 正确处理异步操作和错误冒泡
- 返回标准化的错误响应
原理说明
中间件超时控制的核心原理:在请求处理管道中插入计时器,当超过指定时间未完成时中断后续处理。关键技术点:
- 利用中间件的
next()机制控制执行流程 - 通过
Promise.race()实现主逻辑与超时控制的竞态 - 使用
AbortController终止异步操作(Node.js 15+) - 错误冒泡和统一错误处理
代码示例
// 基于Express的中间件实现
function timeoutMiddleware(timeout = 5000) {
return (req, res, next) => {
const controller = new AbortController();
req.signal = controller.signal;
// 设置超时计时器
const timer = setTimeout(() => {
controller.abort();
const err = new Error('Request Timeout');
err.status = 503;
next(err); // 触发错误处理中间件
}, timeout);
// 主处理逻辑
const mainPromise = new Promise((resolve) => {
res.on('finish', resolve); // 监听响应完成
next(); // 继续后续中间件
});
// 竞态处理
Promise.race([
mainPromise,
new Promise((_, reject) =>
req.signal.addEventListener('abort', () =>
reject(new Error('TimeoutAborted')))
)
]).finally(() => clearTimeout(timer));
};
}
// 使用示例
app.use(timeoutMiddleware(3000));
app.use((err, req, res, next) => {
if (err.message === 'Request Timeout') {
res.status(503).json({ error: 'Service Unavailable' });
}
});最佳实践
- 合理设置超时时间:根据业务类型调整(API建议3-10秒)
- 资源清理:务必清除定时器防止内存泄漏
- 信号传播:通过
AbortSignal通知下游中间件终止操作 - 错误标准化:返回包含
statusCode的统一错误格式 - 日志记录:记录超时请求的路径和方法便于监控
常见错误
- 未清除定时器:导致内存泄漏和意外触发
- 错误处理缺失:超时后未正确终止请求链
- 竞态条件:响应完成后仍执行超时逻辑
- 信号未传递:下游异步操作未接收终止信号
- 时间设置不当:过短导致正常请求被误杀
扩展知识
- 分布式超时控制:在微服务架构中通过链路ID传递超时信息
- 自适应超时:根据历史响应时间动态调整阈值
- 替代方案对比:
connect-timeout:Express官方中间件koa-timeout:Koa的轻量级实现- Nginx层超时:
proxy_read_timeout配置
- 性能影响:每请求一个定时器的开销约0.2ms(Node.js v18)