2013-10-06 4 views
29

Le titre devrait être assez explicite. À des fins de débogage, je voudrais exprimer le code de réponse et le corps pour chaque demande traitée. L'impression du code de réponse est assez facile, mais imprimer le corps de la réponse est plus délicat, car il semble que le corps de la réponse ne soit pas facilement disponible en tant que propriété.corps de réponse d'enregistrement express

Ce qui suit ne fonctionne pas:

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); 

Bien sûr, je pourrais facilement imprimer les réponses au client qui a émis la demande, mais je préférerais faire du côté serveur aussi. PS: Si ça aide, toutes mes réponses sont json, mais j'espère qu'il y a une solution qui fonctionne avec les réponses générales.

Répondre

40

Vous ne savez pas si c'est la solution la plus simple, mais vous pouvez écrire un middleware pour intercepter les données écrites dans la réponse. Assurez-vous de désactiver 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

Merci @ laurent-perrin. Votre réponse fonctionne définitivement. Je vais attendre de voir si quelqu'un a une solution plus simple, sinon je la marquerai comme la réponse acceptée. –

+0

Belle solution, mais que faire si j'ai besoin d'utiliser la compression de réponse? – marmor

+0

cela devrait fonctionner, tant que vous appelez 'app.use' avant le middleware de compression. –

6

Vous pouvez utiliser express-winston et configurer à l'aide:

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

Exemple dans 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

J'ai trouvé la solution la plus simple à ce problème a été d'ajouter une propriété body aux res objet lors de l'envoi de la réponse, qui peut ensuite être consulté par l'enregistreur. J'ajoute ceci à mon propre espace de noms que je maintiens sur les objets req et res pour éviter de nommer les collisions. par exemple.

res[MY_NAMESPACE].body = ... 

J'ai une méthode utilitaire qui formate toutes les réponses à ma réponse standardisée API/JSON, ajoutant ainsi cette ligne de corps exposée il y a de réponse lorsque l'enregistrement se déclenche par onFinished cas de res.

4

J'ai rencontré un problème en utilisant l'approche proposée par Laurent. Parfois, chunk est une chaîne, et provoque donc des problèmes dans l'appel à Buffer.concat(). De toute façon, j'ai trouvé une légère modification des choses fixes:

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

Je viens de me rendre compte que je l'ai fait d'une manière très courte. Mais supprimé le code car il était en train d'imprimer un tableau d'octets. J'aurais dû le convertir en chaîne. :( –

Questions connexes