关于重构的logger,如何使用AllExceptionFilter
来源:9-7 通用业务系统:日志模块代码重构(作业)

abel_meta
2023-11-29
老师,我跟着视频重构了logger模块后,发现AllExceptionFilter开始报错了,正常访问没问题,我故意弄个Exception给它就不行,比如我没登录,就会报错,以下是报错信息:
/Users/yougahei/fc-erp-gpt/node_modules/.pnpm/@nestjs+platform-express@10.2.10_@nestjs+common@10.2.10_@nestjs+core@10.2.10/node_modules/@nestjs/platform-express/adapters/express-adapter.js:28
response.status(statusCode);
^
TypeError: response.status is not a function
at ExpressAdapter.reply (/Users/yougahei/fc-erp-gpt/node_modules/.pnpm/@nestjs+platform-express@10.2.10_@nestjs+common@10.2.10_@nestjs+core@10.2.10/node_modules/@nestjs/platform-express/adapters/express-adapter.js:28:22)
at AllExceptionFilter.catch (/Users/yougahei/fc-erp-gpt/apps/biz-server/src/filters/all-exception.filters.ts:49:21)
at ExceptionsHandler.invokeCustomFilters (/Users/yougahei/fc-erp-gpt/node_modules/.pnpm/@nestjs+core@10.2.10_@nestjs+common@10.2.10_@nestjs+platform-express@10.2.10_reflect-metadata@0.1.13_rxjs@7.8.1/node_modules/@nestjs/core/exceptions/exceptions-handler.js:30:26)
at ExceptionsHandler.next (/Users/yougahei/fc-erp-gpt/node_modules/.pnpm/@nestjs+core@10.2.10_@nestjs+common@10.2.10_@nestjs+platform-express@10.2.10_reflect-metadata@0.1.13_rxjs@7.8.1/node_modules/@nestjs/core/exceptions/exceptions-handler.js:14:18)
at /Users/yougahei/fc-erp-gpt/node_modules/.pnpm/@nestjs+core@10.2.10_@nestjs+common@10.2.10_@nestjs+platform-express@10.2.10_reflect-metadata@0.1.13_rxjs@7.8.1/node_modules/@nestjs/core/router/router-proxy.js:13:35
at processTicksAndRejections (node:internal/process/task_queues:95:5)
main.ts
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app/app.module';
import type {
CorsConfig,
NestConfig,
SwaggerConfig,
} from './common/configs/config.interface';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import 'winston-daily-rotate-file';
import { AllExceptionFilter } from './filters/all-exception.filters';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const logger = app.get(WINSTON_MODULE_NEST_PROVIDER);
app.useLogger(logger);
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);
// Validation
app.useGlobalPipes(new ValidationPipe());
// enable shutdown hook
app.enableShutdownHooks();
// Prisma Client Exception Filter for unhandled exceptions
const httpAdapter = app.get(HttpAdapterHost);
// app.useGlobalFilters(new PrismaClientExceptionFilter(httpAdapter));
app.useGlobalFilters(new AllExceptionFilter(logger, httpAdapter));
const configService = app.get(ConfigService);
const nestConfig = configService.get<NestConfig>('nest');
const corsConfig = configService.get<CorsConfig>('cors');
const swaggerConfig = configService.get<SwaggerConfig>('swagger');
// Swagger Api
if (swaggerConfig.enabled) {
const options = new DocumentBuilder()
.setTitle(swaggerConfig.title || 'Nestjs')
.setDescription(
swaggerConfig.description || 'The nestjs API description'
)
.setVersion(swaggerConfig.version || '1.0')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup(swaggerConfig.path || 'api', app, document);
}
// Cors
if (corsConfig.enabled) {
app.enableCors();
}
await app.listen(process.env.PORT || nestConfig.port || 3000);
}
bootstrap();
all-exception.filters.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
Inject,
LoggerService,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import * as requestIp from 'request-ip';
@Catch()
export class AllExceptionFilter implements ExceptionFilter {
constructor(
@Inject(WINSTON_MODULE_NEST_PROVIDER)
private readonly logger: LoggerService,
private readonly httpAdapterHost: HttpAdapterHost
) {}
catch(exception: unknown, host: ArgumentsHost) {
const { httpAdapter } = this.httpAdapterHost;
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const httpStatus =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const msg: unknown = exception['response'] || 'Internal Server Error';
const responseBody = {
headers: request.headers,
query: request.query,
body: request.body,
params: request.params,
timestamp: new Date().toISOString(),
// 还可以加入一些用户信息
// IP信息
ip: requestIp.getClientIp(request),
exceptioin: exception['name'],
error: msg,
};
this.logger.error('[tomic]', responseBody);
httpAdapter.reply(responseBody, response, httpStatus);
}
}
Http-exception.filters.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
Inject,
LoggerService,
} from '@nestjs/common';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
constructor(
@Inject(WINSTON_MODULE_NEST_PROVIDER)
private logger: LoggerService,
) {}
catch(exception: HttpException, host: ArgumentsHost) {
// 获取上下文
const ctx = host.switchToHttp();
console.log(ctx);
// 获取响应对象
const response = ctx.getResponse<Response>();
console.log(response);
// 获取请求对象
const request = ctx.getRequest<Request>();
// 获取状态码
const status = exception.getStatus();
// 记录日志
this.logger.error(exception.message, exception.stack);
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
// path: request.url,
// method: request.method,
message: exception.message || exception.name,
});
// throw new Error('Method not implemented.');
}
}
写回答
2回答
-
Brian
2023-12-01
根据 NestJS 文档,
reply
方法的第一个参数应该是原始的响应对象(通常是 Express 的Response
对象),第二个参数是您想要发送的响应体,第三个参数是响应状态码。试试下面的代码:
catch(exception: unknown, host: ArgumentsHost) { const { httpAdapter } = this.httpAdapterHost; const ctx = host.switchToHttp(); const response = ctx.getResponse(); const request = ctx.getRequest(); const httpStatus = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; const msg: unknown = exception['response'] || 'Internal Server Error'; const responseBody = { // ... 其他响应体内容 }; this.logger.error('[tomic]', responseBody); // 注意这里的参数顺序 httpAdapter.reply(response, responseBody, httpStatus); }
10 -
Brian
2023-12-01
at ExpressAdapter.reply 错误出在这里,说明传递给httpAdapter.reply的response对象,可能不是express对象,你可以单步调试一下
10
相似问题