Javascript nestjs中间件获取请求/响应正文

Javascript nestjs中间件获取请求/响应正文,javascript,node.js,json,typescript,nestjs,Javascript,Node.js,Json,Typescript,Nestjs,我正在为一个项目使用nestjs,并希望记录尽可能多的信息,其中之一就是每个http请求的响应和请求的主体。我为此做了一个嵌套中间件: import {token} from 'gen-uid'; import { inspect } from 'util'; import { Injectable, NestMiddleware, MiddlewareFunction } from '@nestjs/common'; import { Stream } from 'stream'; impor

我正在为一个项目使用nestjs,并希望记录尽可能多的信息,其中之一就是每个http请求的响应和请求的主体。我为此做了一个嵌套中间件:

import {token} from 'gen-uid';
import { inspect } from 'util';
import { Injectable, NestMiddleware, MiddlewareFunction } from '@nestjs/common';
import { Stream } from 'stream';
import { createWriteStream, existsSync, mkdirSync } from 'fs';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
    logfileStream: Stream;

    constructor() {
        if (!existsSync('./logs')) mkdirSync('./logs');
        this.logfileStream = createWriteStream("./logs/serviceName-"+ new Date().toISOString() + ".log", {flags:'a'});
    }

resolve(...args: any[]): MiddlewareFunction {
    return (req, res, next) => {
        let reqToken = token();
        let startTime = new Date();
        let logreq = {
            "@timestamp": startTime.toISOString(),
            "@Id": reqToken,
            query: req.query,
            params: req.params,
            url: req.url,
            fullUrl: req.originalUrl,
            method: req.method,
            headers: req.headers,
            _parsedUrl: req._parsedUrl,
        }

        console.log(
            "timestamp: " + logreq["@timestamp"] + "\t" + 
            "request id: " + logreq["@Id"] + "\t" + 
            "method:  " + req.method + "\t" +
            "URL: " + req.originalUrl);

        this.logfileStream.write(JSON.stringify(logreq));

        const cleanup = () => {
            res.removeListener('finish', logFn)
            res.removeListener('close', abortFn)
            res.removeListener('error', errorFn)
        }

        const logFn = () => {
            let endTime = new Date();
            cleanup()
            let logres = {
                "@timestamp": endTime.toISOString(),
                "@Id": reqToken,
                "queryTime": endTime.valueOf() - startTime.valueOf(),
            }
            console.log(inspect(res));
        }

        const abortFn = () => {
            cleanup()
            console.warn('Request aborted by the client')
        }

        const errorFn = err => {
            cleanup()
            console.error(`Request pipeline error: ${err}`)
        }

        res.on('finish', logFn) // successful pipeline (regardless of its response)
        res.on('close', abortFn) // aborted pipeline
        res.on('error', errorFn) // pipeline internal error

        next();
    };
}
}
然后我将这个中间件设置为一个全局中间件来记录所有请求,但是查看res和req对象,它们都没有属性

在代码示例中,我将响应对象设置为打印,在我的项目上运行helloworld端点,该端点返回{“message”:“helloworld”} 我得到以下输出:

时间戳:2019-01-09T00:37:00.912Z请求id:2852f925f987方法:获取URL:/hello world

服务器响应{ 域:空, _事件:{finish:[函数:绑定重新配置]}, _事件提示:1, _maxListeners:未定义, 输出:[], 输出编码:[], outputCallbacks:[], 输出大小:0, 可写:对, _最后:错, 升级:错, 错误:错误, 真的, useChunkedEncodingByDefault:true, 发送日期:对, _removedConnection:false, _removedContLen:是的, _雷蒙维特:是的, _contentLength:0, _哈斯博迪:错, _预告片:'', 完成:对, _海德森:是的, 套接字:null, 连接:空, _标题:“HTTP/1.1 304未修改\r\nX由以下驱动:Express\r\nETag:W/“19-c6Hfa5VVP+Ghysj+6y9cPi5QQbk”\r\n日期:Wed,2019年1月9日00:37:00 GMT\r\n连接:保持活动\r\n\r\n”, _onPendingData:[函数:绑定updateOutgoingData], _第100句:错, _期望继续:false, 请求: 收入信息{ _可读状态: 可读状态{ objectMode:false, 高水印:16384, 缓冲区:[对象], 长度:0, 管道:null, 管道:0, 是的, 结束:对, 提交:错误, 阅读:错, 是的, 答案:错, 对,对, 可读性听力:错误, 简历:对, 销毁:错误, defaultEncoding:'utf8', 时间:0,, 雷丁摩尔:没错, 解码器:空, 编码:null}, 可读性:对, 域:空, _事件:{}, _事件提示:0, _maxListeners:未定义, 插座: 插座{ 连接:错, _haderro:false, _句柄:[对象], _父项:null, _主机:空, _readableState:[对象], 可读性:对, 域:空, _事件:[对象], _活动日期:10,, _maxListeners:未定义, _writableState:[对象], 可写:对, AllowAlfOpen:是的, _字节:155, _sockname:null, _pendingData:null, _彭丁编码:'', 服务器:[对象], _服务器:[对象], _空闲时间:5000, _idleNext:[对象], _idlePrev:[对象], _idleStart:12562, _销毁:错误, 解析器:[对象], on:[函数:socketOnWrap], _暂停:错, 读:[函数], _消费:是的, _httpMessage:null, [符号(异步ID)]:151, [符号(字节读取)]:0, [符号(异步ID)]:153, [符号(triggerAsyncId)]:151}, 连接: 插座{ 连接:错, _haderro:false, _句柄:[对象], _父项:null, _主机:空, _readableState:[对象], 可读性:对, 域:空, _事件:[对象], _活动日期:10,, _maxListeners:未定义, _writableState:[对象], 可写:对, AllowAlfOpen:是的, _字节:155, _sockname:null, _pendingData:null, _彭丁编码:'', 服务器:[对象], _服务器:[对象], _空闲时间:5000, _idleNext:[对象], _idlePrev:[对象], _idleStart:12562, _销毁:错误, 解析器:[对象], on:[函数:socketOnWrap], _暂停:错, 读:[函数], _消费:是的, _httpMessage:null, [符号(异步ID)]:151, [符号(字节读取)]:0, [符号(异步ID)]:153, [符号(triggerAsyncId)]:151}, httpVersionMajor:1, httpVersionMinor:1, httpVersion:'1.1', 完全正确, 标题: {host:'localhost:5500', “用户代理”:“Mozilla/5.0(X11;Ubuntu;Linux x86_64;rv:64.0)Gecko/20100101 Firefox/64.0”, accept:'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8', ‘接受语言’:‘en-US,en;q=0.5’, “接受编码”:“gzip,deflate”, 连接:“保持活力”, “升级不安全请求”:“1”, “如果不匹配”:“W/”19-c6Hfa5VVP+Ghysj+6y9cPi5QQbk”, 原始标题: [“主机”, '本地主机:5500', “用户代理”, “Mozilla/5.0(X11;Ubuntu;Linux x86_64;rv:64.0)Gecko/20100101 Firefox/64.0”, “接受”, 'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8', “接受语言”, ‘en-US,en;q=0.5’, “接受编码”, “gzip,deflate”, “连接”, "活下去",, “升级不安全的请求”, '1', '如果没有匹配', “W/“19-c6Hfa5VVP+Ghysj+6Y9CPI5QBK”], 预告片:{}, Raw:[], 升级:false, url:“/hello world”, 方法:“GET”, 状态代码:null, statusMessage:null, 客户: 插座{ 连接:错, _遮光罩
var mung = require('express-mung');
app.use(mung.json(
  function transform(body, req, res) {
    console.log(body); // or whatever logger you use
    return body;
  }
));
providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: HttpInterceptor,
    }
]
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class HttpInterceptor implements NestInterceptor {
  private readonly logger = new Logger(HttpInterceptor.name);

  intercept(
    context: ExecutionContext,
    next: CallHandler<any>,
  ): Observable<any> | Promise<Observable<any>> {
    return next.handle().pipe(
      map(data => {
        this.logger.debug(data);
        return data;
      }),
    );
  }
}