2013-10-06 92 views
29

標題應該是相當自我解釋。快速記錄響應主體

爲了調試的目的,我想表達打印每個請求服務的響應代碼和正文。打印響應代碼很簡單,但打印響應主體更復雜,因爲它看起來響應主體不容易作爲屬性提供。

下不起作用:

var express = require('express'); 
var app = express(); 

// define custom logging format 
express.logger.format('detailed', function (token, req, res) {          
    return req.method + ': ' + req.path + ' -> ' + res.statusCode + ': ' + res.body + '\n'; 
}); 

// register logging middleware and use custom logging format 
app.use(express.logger('detailed')); 

// setup routes 
app.get(..... omitted ...); 

// start server 
app.listen(8080); 

當然,我可以輕鬆地打印在誰發出請求的客戶端的響應,但我寧願在服務器端也做的事情。 PS:如果有幫助,我所有的回覆都是json,但是希望有一個解決方案可以與一般回覆一起使用。

回答

40

不知道這是否是最簡單的解決方案,但可以編寫一箇中間件來攔截寫入響應的數據。確保你禁用app.compress()

function logResponseBody(req, res, next) { 
    var oldWrite = res.write, 
     oldEnd = res.end; 

    var chunks = []; 

    res.write = function (chunk) { 
    chunks.push(chunk); 

    oldWrite.apply(res, arguments); 
    }; 

    res.end = function (chunk) { 
    if (chunk) 
     chunks.push(chunk); 

    var body = Buffer.concat(chunks).toString('utf8'); 
    console.log(req.path, body); 

    oldEnd.apply(res, arguments); 
    }; 

    next(); 
} 

app.use(logResponseBody); 
+0

謝謝@勞倫特 - 佩林。你的答案肯定有效。我會等待,看看有人有一個更簡單的解決方案,否則我會將其標記爲接受的答案。 –

+0

不錯的解決方案,但如果我需要使用響應壓縮呢? – marmor

+0

只要你在壓縮中間件之前調用'app.use',它應該可以正常工作。 –

6

您可以使用express-winston和使用配置:

expressWinston.requestWhitelist.push('body'); 
expressWinston.responseWhitelist.push('body'); 

例中的CoffeeScript:

expressWinston.requestWhitelist.push('body') 
expressWinston.responseWhitelist.push('body') 
app.use(expressWinston.logger({ 
     transports: [ 
     new winston.transports.Console({ 
      json: true, 
      colorize: true 
     }) 
     ], 
     meta: true, // optional: control whether you want to log the meta data about the request (default to true) 
     msg: "HTTP {{req.method}} {{req.url}}", // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}" 
     expressFormat: true, // Use the default Express/morgan request formatting, with the same colors. Enabling this will override any msg and colorStatus if true. Will only output colors on transports with colorize set to true 
     colorStatus: true, // Color the status code, using the Express/morgan color palette (default green, 3XX cyan, 4XX yellow, 5XX red). Will not be recognized if expressFormat is true 
     ignoreRoute: function (req, res) { return false; } // optional: allows to skip some log messages based on request and/or response 
    })); 
0

,我發現這個問題最簡單的辦法是到body屬性添加到R​​ES對象在發送響應時可以稍後由記錄器訪問。我將它添加到我自己的名稱空間中,並保留在req和res對象上以避免命名衝突。例如

res[MY_NAMESPACE].body = ... 

我有格式化所有答覆我的標準化API/JSON響應,因此增加這一個襯墊有暴露的響應主體時,記錄得到由onFinished事件水庫觸發一個實用的方法。

4

我遇到了一個使用Laurent建議的方法的問題。有時chunk是一個字符串,因此在調用Buffer.concat()時會導致問題。無論如何,我發現一個微小的修改固定的東西:

function logResponseBody(req, res, next) { 
    var oldWrite = res.write, 
     oldEnd = res.end; 

    var chunks = []; 

    res.write = function (chunk) { 
    chunks.push(new Buffer(chunk)); 

    oldWrite.apply(res, arguments); 
    }; 

    res.end = function (chunk) { 
    if (chunk) 
     chunks.push(new Buffer(chunk)); 

    var body = Buffer.concat(chunks).toString('utf8'); 
    console.log(req.path, body); 

    oldEnd.apply(res, arguments); 
    }; 

    next(); 
} 

app.use(logResponseBody); 
+0

我剛剛意識到我以某種方式很快完成了它。但是從打印字節數組開始刪除了代碼。我應該將其轉換爲字符串。 :( –