/** * HttpException filter. * @file 全局异常过滤器 * @module filters/http.filter * @author zhxiao1124 */ import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from "@nestjs/common"; import { Request, Response } from "express"; import { LogsService } from "@src/logs/logs.service"; import { getRequestCost } from "@app/utils/request-context.util"; @Catch() export class HttpExceptionFilter implements ExceptionFilter { constructor(private readonly logsService: LogsService) {} catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const request = ctx.getRequest(); const response = ctx.getResponse(); const statusCode = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; const message = this.getMessage(exception, statusCode); const requestId = request.requestId ?? ""; const costMs = getRequestCost(request); this.logsService.recordRequest({ requestId, method: request.method, path: request.originalUrl ?? request.url, query: request.query, body: request.body, statusCode, responseCode: statusCode, message, costMs, userId: request.user?.id, adminId: request.adminId, ip: request.ip, userAgent: request.get("user-agent"), errorStack: exception instanceof Error ? exception.stack : undefined, }); response.status(statusCode).json({ code: statusCode, data: {}, message, timestamp: Date.now(), requestId, cost: `${costMs}ms`, }); } private getMessage(exception: unknown, statusCode: number): string { if (exception instanceof HttpException) { const response = exception.getResponse(); if (typeof response === "string") { return response; } if (response && typeof response === "object" && "message" in response) { const message = (response as { message: string | string[] }).message; return Array.isArray(message) ? message.join("; ") : message; } } if (exception instanceof Error && statusCode === HttpStatus.INTERNAL_SERVER_ERROR) { return exception.message || "Internal server error"; } return "Internal server error"; } }