如何在NestJS/GraphQL中拦截Apollo标准HTTP错误?
在NestJS/GraphQL中拦截或修改Apollo的标准HTTP错误
这个问题我之前踩过坑!其实核心原因是你遇到的HttpQueryError(比如"GET query missing")和常规GraphQL错误不在同一个处理阶段,所以常规的GraphQL异常过滤器根本碰不到它。
为什么常规GraphQL过滤器拦截不到?
你平时用的GraphQL异常过滤器,作用是拦截GraphQL执行阶段(比如Resolver里抛出的异常、Schema验证错误等)的错误。而HttpQueryError是Apollo Server在还没进入GraphQL请求处理流程时就抛出的——比如当你用GET请求访问GraphQL端点(且没有符合要求的查询参数),Apollo会直接在HTTP层面拒绝请求,还没走到GraphQL的执行逻辑,自然不会被GraphQL过滤器捕获。
具体解决方案
下面给你三种可行的实现方式,按需选择:
1. 使用Nest全局HTTP异常过滤器
因为这类错误本质是HTTP级别的异常,所以可以用Nest的全局HTTP异常过滤器来捕获并修改响应:
首先创建全局过滤器:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; import { Response } from 'express'; @Catch() export class GlobalHttpExceptionFilter implements ExceptionFilter { catch(exception: any, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); // 识别Apollo的HttpQueryError if (exception.name === 'HttpQueryError') { return response.status(exception.statusCode).json({ statusCode: exception.statusCode, message: '请使用POST请求访问GraphQL接口,并携带正确的查询参数', error: exception.message, }); } // 处理其他HTTP异常 if (exception instanceof HttpException) { const status = exception.getStatus(); return response.status(status).json(exception.getResponse()); } // 兜底处理未知错误 response.status(500).json({ statusCode: 500, message: '服务器内部错误', }); } }
然后在main.ts中注册全局过滤器:
async function bootstrap() { const app = await NestFactory.create(AppModule); // 注册全局HTTP异常过滤器 app.useGlobalFilters(new GlobalHttpExceptionFilter()); await app.listen(8080); } bootstrap();
2. 自定义Apollo Server插件
Apollo允许通过插件介入请求的生命周期,包括捕获前置的HTTP错误:
创建Apollo插件:
import { ApolloServerPlugin, GraphQLRequestContext } from '@apollo/server'; export class ApolloHttpErrorInterceptorPlugin implements ApolloServerPlugin { async requestDidStart(requestContext: GraphQLRequestContext) { return { async didEncounterErrors(requestContext) { // 查找是否存在HttpQueryError const httpError = requestContext.errors?.find( err => err.extensions?.exception?.name === 'HttpQueryError' ); if (httpError) { // 修改错误信息 httpError.message = '自定义的GET请求错误提示'; // 自定义响应状态码和内容 requestContext.response?.http?.status = 400; requestContext.response?.http?.body = JSON.stringify({ statusCode: 400, message: 'GraphQL接口仅支持POST请求,请检查请求方式', }); } }, }; } }
然后在GraphQL模块中配置插件:
import { Module } from '@nestjs/common'; import { GraphQLModule } from '@nestjs/graphql'; import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; import { ApolloHttpErrorInterceptorPlugin } from './apollo-http-error.plugin'; @Module({ imports: [ GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, playground: false, autoSchemaFile: true, // 注册自定义插件 plugins: [new ApolloHttpErrorInterceptorPlugin()], }), ], }) export class AppModule {}
3. 利用Apollo的formatError配置
如果你只需要修改错误的返回格式,也可以通过formatError来处理(注意:部分版本的Apollo可能需要确认是否能捕获到前置错误):
GraphQLModule.forRoot<ApolloDriverConfig>({ driver: ApolloDriver, playground: false, autoSchemaFile: true, formatError: (error) => { // 识别HttpQueryError if (error.extensions?.exception?.name === 'HttpQueryError') { return { message: '自定义的请求错误信息', statusCode: error.extensions.exception.statusCode, extensions: { ...error.extensions, customInfo: '仅支持POST请求访问GraphQL端点', }, }; } // 其他GraphQL错误保持默认处理 return error; }, })
内容的提问来源于stack exchange,提问作者Lewsmith
相关产品推荐
相关产品推荐

