如何在 NestJS 中记录所有 Axios 外部 http 请求

Posted

技术标签:

【中文标题】如何在 NestJS 中记录所有 Axios 外部 http 请求【英文标题】:How to log all Axios external http requests in NestJS 【发布时间】:2019-06-11 06:02:56 【问题描述】:

我希望能够使用完整的 url、标头等记录每个 axios 请求,但目前没有找到这样做的方法。

到目前为止,我所做的是基于answer 来编写一个 Http 拦截器

export class HttpLoggerInterceptor implements NestInterceptor 
  intercept(
    context: ExecutionContext,
    call$: Observable<any>,
  ): Observable<any> 
    return call$.pipe(
      map(data => 
        // pipe call to add / modify header(s) after remote method
        const req = context.switchToHttp().getRequest();
        return data;
      ),
    );
  

现在我在调试时浏览对象 reqcontext 道具,但看不到 Asios 请求 url 等。除非我错过了。

我的控制器路由(在这种情况下为api/data)发生了 N 个 http 外部调用,但拦截器仅拦截控制器控制器调用而不是 Axios 调用。

有什么想法吗?

context对象:

args:Array(2) [IncomingMessage, ServerResponse]
constructorRef:class AppController  … 
getRequest:() => …
getResponse:() => …
handler:data()  … 
__proto__:Object constructor: , getClass: , getHandler: , …

那是req:

_dumped:false
_events:Object 
_eventsCount:0
_maxListeners:undefined
_parsedOriginalUrl:Url protocol: null, slashes: null, auth: null, …
_parsedUrl:Url protocol: null, slashes: null, auth: null, …
_readableState:ReadableState objectMode: false, highWaterMark: 16384, buffer: BufferList, …
baseUrl:""
body:Object 
client:Socket connecting: false, _hadError: false, _handle: TCP, …
complete:true
connection:Socket connecting: false, _hadError: false, _handle: TCP, …
destroyed:false
fresh:false
headers:Object accept: "application/json, text/plain, */*", user-agent: "axios/0.18.0", host: "localhost:3000", …
host:"localhost"
hostname:"localhost"
httpVersion:"1.1"
httpVersionMajor:1
httpVersionMinor:1
ip:"::ffff:127.0.0.1"
ips:Array(0)
method:"GET"
next:function next(err)  … 
originalUrl:"/api/data"
params:Object 
__proto__:Object constructor: , __defineGetter__: , __defineSetter__: , …
path:"/api/data"
protocol:"http"
query:Object 
rawHeaders:Array(8) ["Accept", "application/json, text/plain, */*", "User-Agent", …]
rawTrailers:Array(0) []
readable:true
readableBuffer:BufferList
readableFlowing:null
readableHighWaterMark:16384
readableLength:0
res:ServerResponse _events: Object, _eventsCount: 1, _maxListeners: undefined, …
route:Route path: "/api/data", stack: Array(1), methods: Object
secure:false
socket:Socket connecting: false, _hadError: false, _handle: TCP, …
stale:true
statusCode:null
statusMessage:null
subdomains:Array(0)
trailers:Object 
upgrade:false
url:"/api/data"
xhr:false

【问题讨论】:

@KimKern 刚刚对您的回答发表了评论 【参考方案1】:

Nest.js-Interceptors 只处理由控制器处理的请求和发出的响应。如果您在处理控制器请求时使用 Axios 发出 http 请求,它们将不会被拦截器处理。


Axios 拦截器

HttpService 直接通过get axiosRef() 公开其axios 实例。有了它,你可以添加一个axios interceptor

this.httpService.axiosRef.interceptors.request.use(config =>  /*...*/ return config )

例如,您可以在 AppModuleonModuleInit() 中执行此操作。


代理到外观

作为替代方案,您可以创建一个HttpService 外观,记录请求并将所有调用委托给内置的HttpService

@Injectable()
export class MyHttpService 
  private logger: Logger = new Logger(MyHttpService.name);

  constructor (private httpService: HttpService) 
  
  public get<T = any>(url: string, config?: AxiosRequestConfig): Observable<AxiosResponse<T>> 
    this.logger.log(url, config);
    return this.httpService.get(url, config)
       .pipe(tap(response => this.logger.log(response)));
  

  // ... all the other methods you need.


您可以创建自己的LoggingHttpModule,导入内置的HttpModule 并导出您的MyHttpService

【讨论】:

您会推荐哪种方法?似乎第二种方法涉及更多代码。如果您采用Axios Interceptor 方法,您会在哪里粘贴this.httpService.axiosRef.interceptors.request.use(config =&gt; console.log(config)); 代码? &gt;You can for example do that in the onModuleInit() of your AppModule - 你能提供更多背景信息吗? 看看这个答案的第二部分,其中解释了OnModuleInit。 ***.com/a/53484892/4694994 是的,我建议使用 axios 拦截器解决方案。 在 NestJS 的 typescript 版本中,我需要使用稍有改动的拦截器 this.httpService.axiosRef.interceptors.request.use((config: AxiosRequestConfig) =&gt; console.log(config); return config; ); 刚尝试实现axios拦截器,遇到了这个问题***.com/questions/68869611/…【参考方案2】:
npm i @types/morgan

npm i morgan

然后

import * as morgan from 'morgan';

export class AppModule implements NestModule 
  configure(consumer: MiddlewareConsumer) 
    consumer
      .apply(morgan('combined'))
      .forRoutes('*');
  

【讨论】:

以上是关于如何在 NestJS 中记录所有 Axios 外部 http 请求的主要内容,如果未能解决你的问题,请参考以下文章

在 NestJS 中缓存 axios httpService

Axios.all 在 Nestjs 中可用吗?

如何使用@nestjs/axios 发出 api Get 请求

NestJS:如何使用另一个装饰器自动记录@MessagePattern 的输入数据?

如何在带有typeorm的nestjs项目中使用外部实体?

Nestjs 使用 axios