有人能解释一下howtonode的函数包装习惯用法吗?

Could someone explain a function wrapping idiom from howtonode?

本文关键字:包装 函数 习惯 惯用法 howtonode 一下 能解释      更新时间:2023-09-26

我最近开始使用node.js, express &mongodb。由于express使用connect提供中间件支持,我开始阅读中间件和连接。

我在howtonode.org上看到了下面的例子:

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

的调用中

那是什么意思?

它拦截对res.writeHead的调用,添加一些日志记录,然后将调用委托给原始res.writeHead

它就像一个超简单的AOP方法拦截。

让我们分解这里发生的事情

wrapping idiom to hook into the call to writeHead

在标准的express流程中,接收请求(req)并准备响应(res)。(reqres)对可以通过一系列过滤器级联,这些过滤器可以修改req并准备res

在流中的某一点,res将被认为准备充分,响应的标头可以发送到客户端。函数res。为此将调用writeHead*。

这个函数的原型是function (code, headers),为了记录将要发送的头,你需要在这个时刻钩住代码并做一个

console.log("Response " + code + " " + JSON.stringify(headers));
在某种程度上,如果代码中的原始函数是
res.writeHead = function(code, headers) {
    // original code
}

您希望将此代码替换为

res.writeHead = function(code, headers) {
    console.log("Response " + code + " " + JSON.stringify(headers));
    // original code
}

在某种程度上,您希望在writeHead函数的开头"插入"一段代码。

但是您不应该尝试修改原始的writeHead代码,因为您可能甚至不知道这些代码是在哪里编写的,并且您不想开始查找。因此,您希望劫持这个函数:当一段代码将调用res.writeHead时,您希望被调用的是自己的函数。

一种方法就是

return function logItHandle(req, res, next) {
   res.writeHead = function (code, headers) {
       console.log("Response " + code + " " + JSON.stringify(headers));
   }
   next(); 
}

,但是如果你只这样做,你就会遇到一些麻烦,因为原始的writeHead代码丢失了,不会被调用。因此,标头将被记录,但不会发送到客户端!

你需要一种方法来"记住"原始代码,并在你的writeHead变体的末尾调用它:

return function logItHandle(req, res, next) {
   // save the original writeHead function so that it can be referenced in the closure
   var originalWriteHead = res.writeHead; 
   res.writeHead = function (code, headers) {
       // log the response headers
       console.log("Response " + code + " " + JSON.stringify(headers));
       // make as if our hook never existed in the flow
       res.writeHead = originalWriteHead ;
       // call the original writeHead because otherwise the external code
       // called our implementation of writeHead instead of the original code
       res.writeHead(code, headers);
   }
   next(); 
}