如何超时缓慢连接中间件而不是返回节点响应?

时间:2017-01-18 02:30:53

标签: javascript node.js connect node-http-proxy

我有一个Node服务器,它使用Connect来插入一些试图从node-http-proxy转换响应流的中间件。偶尔这种转换可能会非常缓慢,在这种情况下,最好只返回一个不包含转换的响应,或者包括它们的部分应用。

在我的应用程序中,我尝试在转换中间件的上下文中使用setTimeout在几毫秒后调用next。这通常有效但暴露了竞争条件,如果中间件已经调用next然后setTimeout触发并执行相同的错误,则会出现以下情况:Error: Can't set headers after they are sent.

最终我将setTimeout演变为以next实例作为其第一个参数调用Error,然后在我的中间件链中将捕获该错误并假设res.headersSentfalse会开始通过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();
    }
  });
});

3 个答案:

答案 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.timeoutBluebird图书馆中的QPromise.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()。

如果响应转换更快,它会清除超时以防止它稍后再运行。