diff --git a/src/app.config.ts b/src/app.config.ts index bde4809d..3f57baa5 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -69,9 +69,13 @@ export const CLUSTER = { /** Is main cluster in PM2 */ export const isMainCluster = process.env.NODE_APP_INSTANCE && parseInt(process.env.NODE_APP_INSTANCE) === 0 - export const isMainProcess = cluster.isPrimary || isMainCluster +export const DEBUG_MODE = { + httpRequestVerbose: + argv.httpRequestVerbose ?? argv.http_request_verbose ?? true, +} + if (!CLUSTER.enable || cluster.isPrimary || isMainCluster) { console.log(argv) console.log('cwd: ', cwd) diff --git a/src/processors/helper/helper.http.service.ts b/src/processors/helper/helper.http.service.ts index 9111e833..8ccfd427 100644 --- a/src/processors/helper/helper.http.service.ts +++ b/src/processors/helper/helper.http.service.ts @@ -1,28 +1,40 @@ -import axios, { AxiosInstance } from 'axios' -import axiosRetry from 'axios-retry' +import axios, { AxiosInstance, AxiosRequestConfig } from 'axios' +import retryAxios from 'axios-retry' import { Injectable, Logger } from '@nestjs/common' -import { AXIOS_CONFIG } from '~/app.config' +import { AXIOS_CONFIG, DEBUG_MODE } from '~/app.config' import { RedisKeys } from '~/constants/cache.constant' import { getRedisKey } from '~/utils' import { version } from '../../../package.json' import { CacheService } from '../cache/cache.service' +declare module 'axios' { + interface AxiosRequestConfig { + __requestStartedAt?: number + __requestEndedAt?: number + __requestDuration?: number + + __debugLogger?: boolean + } +} + @Injectable() export class HttpService { private http: AxiosInstance private logger: Logger constructor(private readonly cacheService: CacheService) { this.logger = new Logger(HttpService.name) - this.http = axios.create({ - ...AXIOS_CONFIG, - headers: { - 'user-agent': `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 MX-Space/${version}`, - }, - }) - axiosRetry(this.http, { + this.http = this.bindDebugVerboseInterceptor( + axios.create({ + ...AXIOS_CONFIG, + headers: { + 'user-agent': `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 MX-Space/${version}`, + }, + }), + ) + retryAxios(this.http, { retries: 3, retryDelay: (count) => { return 1000 * count @@ -31,6 +43,26 @@ export class HttpService { }) } + private axiosDefaultConfig: AxiosRequestConfig = { + ...AXIOS_CONFIG, + headers: { + 'user-agent': `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 MX-Space/${version}`, + }, + 'axios-retry': { + retries: 3, + retryDelay: (count) => { + return 1000 * count + }, + shouldResetTimeout: true, + }, + } + + extend(config: AxiosRequestConfig) { + return this.bindDebugVerboseInterceptor( + axios.create({ ...this.axiosDefaultConfig, ...config }), + ) + } + /** * 缓存请求数据,现支持文本 * @param url @@ -55,4 +87,79 @@ export class HttpService { public get axiosRef() { return this.http } + + private bindDebugVerboseInterceptor($http: AxiosInstance) { + if (!DEBUG_MODE.httpRequestVerbose) { + return $http + } + $http.interceptors.request.use((req) => { + if (!req.__debugLogger) { + return req + } + req.__requestStartedAt = performance.now() + + this.logger.log( + `HTTP Request: [${req.method?.toUpperCase()}] ${req.baseURL || ''}${ + req.url + } +params: ${this.prettyStringify(req.params)} +data: ${this.prettyStringify(req.data)}`, + ) + + return req + }) + $http.interceptors.response.use( + (res) => { + if (!res.config.__debugLogger) { + return res + } + const endAt = performance.now() + res.config.__requestEndedAt = endAt + res.config.__requestDuration = + res.config?.__requestStartedAt ?? + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + endAt - res.config!.__requestStartedAt! + this.logger.log( + `HTTP Response ${`${res.config.baseURL || ''}${ + res.config.url + }`} +${res.config.__requestDuration.toFixed( + 2, + )}ms: \n${this.prettyStringify(res.data)} `, + ) + return res + }, + (err) => { + const res = err.response + + const error = Promise.reject(err) + if (!res) { + this.logger.error( + `HTTP Response Failed ${err.config.url || ''}, Network Error: ${ + err.message + }`, + ) + return error + } + this.logger.error( + chalk.red( + `HTTP Response Failed ${`${res.config.baseURL || ''}${ + res.config.url + }`}\n${this.prettyStringify(res.data)}`, + ), + ) + + return error + }, + ) + return $http + } + + private bindInterceptors($http: AxiosInstance) { + this.bindDebugVerboseInterceptor($http) + return $http + } + + private prettyStringify(data: any) { + return JSON.stringify(data, null, 2) + } }