我有一个Node服务器,它使用Connect来插入一些试图从node-http-proxy转换响应流的中间件。偶尔这种转换可能会非常缓慢,在这种情况下,最好只返回一个不包含转换的响应,或者包括它们的部分应用。
在我的应用程序中,我尝试在转换中间件的上下文中使用setTimeout
在几毫秒后调用next
。这通常有效但暴露了竞争条件,如果中间件已经调用next
然后setTimeout
触发并执行相同的错误,则会出现以下情况:Error: Can't set headers after they are sent.
最终我将setTimeout
演变为以next
实例作为其第一个参数调用Error
,然后在我的中间件链中将捕获该错误并假设res.headersSent
是false
会开始通过res.end.call(res)
发送回复。这很有效,令人惊讶的是,我可以将超时设置为几乎为零,响应将更快地完成并且完成。
我觉得这最后一种方法有点像黑客并且不能免于相同的竞争条件,但似乎更有弹性。所以我想知道Node和Connect有什么样的惯用方法来处理这类事情。
如何进行慢速中间件的超时并简单地返回响应流?
目前这似乎做了我想要的,或多或少,但又感觉有点粗糙。
let resTimedout = false;
const timeout = setTimeout(() => {
if (!resTimedout) {
resTimedout = true;
next();
}
}, 100);
getSelectors(headers, uri, (selectors) => {
const resSelectors = Object.keys(selectors).map((selector) => {
...
};
const rewrite = resRewrite(resSelectors);
rewrite(req, res, () => {
if (!resTimedout) {
resTimedout = true;
clearTimeout(timeout);
next();
}
});
});
答案 0 :(得分:0)
setTimeout返回超时的id,因此您可以运行传入id的clearTimeout。因此,当转换完成后,只需在下次调用之前清除超时。
var a = setTimeout(()=>{}, 3000);
clearTimeout(a);
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
答案 1 :(得分:0)
使用async.timeout
或Bluebird图书馆中的Q或Promise.timeout
答案 2 :(得分:0)
您可以消除对全局变量的需求,并根据请求做出决定:
const rewrite = resRewrite(resSelectors);
rewrite(req, res, () => {
// set a timer to fail the function early
let timer = setTimeout(() => {
timer = null;
next();
}, 100);
// do the slow response transformation
transformResponse((err, data) => { // eg. callback handler
clearTimeout(timer);
if (timer) next();
});
});
工作原理
如果计时器首先结束,它将自身设置为null并调用next()。当转换函数结束时,它将看到超时为空,而不是调用next()。
如果响应转换更快,它会清除超时以防止它稍后再运行。