Express.js实现请求超时后出现未捕获Promise拒绝警告求助
Express请求超时后避免重复响应的解决方案
你的问题核心是:超时回调已经发送了响应,后续异步任务完成后再次调用res.json()导致重复响应,触发uncaughtPromiseRejectionWarning。以下是具体解决思路和代码修改方案:
1. 标记请求状态,阻止后续响应
在超时回调中给请求对象添加一个超时标记,路由处理时先检查这个标记,若已超时则跳过响应发送。
修改超时中间件:
app.use(function(req, res, next){ res.setTimeout(5000, function(){ console.log('Request has timed out.'); req.timedOut = true; // 标记请求已超时 return res.json({success: false, message: "request timeout"}); }); console.log("calling next"); next(); });
修改路由处理逻辑:
app.get('/', async(req, res) => { const data = await asyncWork(); if (req.timedOut) return; // 已超时则终止后续操作 res.json(data); });
2. 取消异步任务(优化方案)
如果异步任务支持取消,建议在超时后主动中止任务,避免不必要的资源消耗。Node.js 15+支持AbortController来实现这一点:
首先修改异步任务函数,接收中止信号:
const asyncWork = (signal) => { return new Promise((resolve,reject) => { const timer = setTimeout(() => { console.log("after 10 sec"); resolve({"id": 1}); },10000); // 监听中止信号,触发时清理资源并拒绝Promise signal.addEventListener('abort', () => { clearTimeout(timer); reject(new Error("Request timed out")); }); }); };
然后更新中间件和路由:
app.use(function(req, res, next){ const controller = new AbortController(); req.signal = controller.signal; res.setTimeout(5000, function(){ console.log('Request has timed out.'); req.timedOut = true; controller.abort(); // 触发异步任务中止 return res.json({success: false, message: "request timeout"}); }); console.log("calling next"); next(); }); app.get('/', async(req, res) => { try { const data = await asyncWork(req.signal); if (req.timedOut) return; res.json(data); } catch (err) { // 仅处理非超时中止的错误 if (err.name !== 'AbortError') { res.status(500).json({success: false, message: "Server error"}); } } });
3. 全局捕获未处理的Promise拒绝(兜底方案)
为了避免控制台出现警告,可以在全局层面捕获未处理的Promise拒绝,作为兜底措施:
process.on('unhandledRejection', (reason, promise) => { console.log('未处理的Promise拒绝:', promise, '原因:', reason); // 可在此添加日志上报等操作 });
内容的提问来源于stack exchange,提问作者AYUSH KUMAR ARYAL
相关产品推荐
相关产品推荐

