0

我试图了解中间件的工作原理,特别是 NodeJS 的 Connect 模块。我正在浏览这个http://howtonode.org/connect-it并找到了这个例子:

module.exports = function logItSetup() {

  // Initialize the counter
  var counter = 0;

  return function logItHandle(req, res, next) {
    var writeHead = res.writeHead; // Store the original function

    counter++;

    // Log the incoming request
    console.log("Request " + counter + " " + req.method + " " + req.url);

    // Wrap writeHead to hook into the exit path through the layers.
    res.writeHead = function (code, headers) {
      res.writeHead = writeHead; // Put the original back

      // Log the outgoing response
      console.log("Response " + counter + " " + code + " " + JSON.stringify(headers));

      res.writeHead(code, headers); // Call the original
    };

    // Pass through to the next layer
    next();
  };
};

所以我知道它会记录传入的请求和响应。但是即使有文章中的以下解释,我仍然不明白您需要用替换函数替换 writeHead:

“设置函数是设置中间件跨请求使用的变量的好地方。在这种情况下,我们正在初始化记录器的计数器。

在处理程序中,我们使用包装习语来挂钩对 writeHead 的调用。在 JavaScript 中,函数是值,就像其他任何东西一样。因此,包装函数的一个好方法是将对原始实现的引用存储在闭包变量中。将函数替换为新函数,并在新函数的第一行中,将旧函数定义放回原处。然后在替换函数的最后一行调用原来的。这是挂钩现有对象方法的一种简单而有效的方法,因为它们只是按名称查找属性,而不是对实际函数对象的引用。

独立的 console.log 调用将在每个请求周期开始时调用,嵌套的 console.log 将在退出时通过嵌套的 writeHead 函数调用。”

4

1 回答 1

1

每次有传入请求时,它都会通过堆栈中间件。这些是简单的函数,需要 3 个参数req, res, next,有点像这样:

function someMiddleware(req,res,next){
  // do stuff with request & response...

  // You need to call next to keep going through the stack
  next(); 
}

在您的示例中,您可以像这样使用模块:

connect()
.use(function(req,res,next){
  //some other handler
  // ...
  // Call next
  next();
})
.use(logInSetup) //Assuming you named it like this

该模块returns的功能正是堆栈中间件所期望的。这就是连接的方式......基本上是相同的想法。

writeHead函数存储在一个变量中,因此您可以调用console.log每个请求,然后调用实际函数。考虑到writeHead在调用此函数时不会调用它,而是res.writeHead从其他地方调用时。这是一种(非常聪明的)修改函数而不改变其原始实现的方法。

一个非常简单的例子:

//Assume this function is a dependency and cannot be alter
function sumNums(a,b){
  return a + b;
}

var sumNums_copy = sumNums;

function sumNums(a,b) {
  console.log('Log and the sum');
  sumNums_copy(a,b);
};

sumNums_copy(2,2); // sums
sumNums(2,2); // sums and logs

函数是 javascript 中的第一类对象,这意味着它们可以作为参数传递给其他函数、从函数返回或存储在变量中。

于 2013-09-23T22:49:53.100 回答