使用express-graphql时,如何在GraphQL报错时修改HTTP状态码?
问题:通过
throw Error修改HTTP状态码实现前端本地化错误信息是否可行?如何实现? 我希望在通过throw new Error("this is my error.")抛出错误时修改HTTP状态码,目的是为了在前端返回本地化错误信息,请问是否可行?该如何实现?
我尝试了以下代码,但出现了错误:
在查询/变更中抛出错误:
throw new Error("Not Authorized.")
服务器代码:
graphql_router.use("/", graphqlHTTP((req, res, graphQLParams) => { return { schema: schema, graphiql: process.env.NODE_ENV === 'development', contextValue: { ip: req.ip }, customFormatErrorFn: (error) => { try { return res.status(500).json({ error: error.message }) } catch { return error; } }, } }));
错误信息:
backend/node_modules/express/lib/response.js:1150 : JSON.stringify(value); ^ TypeError: Converting circular structure to JSON --> starting at object with constructor 'Socket' | property '_writableState' -> object with constructor 'WritableState' | property 'afterWriteTickInfo' -> object with constructor 'Object' --- property 'stream' closes the circle at JSON.stringify (<anonymous>) at stringify (/Users/tarikulkerjs/Desktop/projects/blindlook/backend/node_modules/express/lib/response.js:1150:12) at ServerResponse.json (/Users/tarikulkerjs/Desktop/projects/blindlook/backend/node_modules/express/lib/response.js:271:14) at graphqlMiddleware (/Users/tarikulkerjs/Desktop/projects/blindlook/backend/node_modules/express-graphql/index.js:198:22) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) Node.js v18.16.0 [nodemon] app crashed - waiting for file changes before starting...
回答
可行,但你当前的写法存在逻辑错误:customFormatErrorFn的作用是格式化错误对象,返回给GraphQL中间件用于构建最终响应,不是直接发送HTTP响应。你直接调用res.status().json()会返回res对象本身,而res内部包含循环引用的结构(比如Socket、WritableState等),当GraphQL中间件尝试序列化这个返回值时,就会触发你看到的循环引用错误。
正确实现步骤如下:
1. 定义带状态码的自定义错误类
通过自定义错误类,在抛出错误时携带HTTP状态码信息:
class HttpError extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; this.name = 'HttpError'; // 标记错误类型,方便后续识别 } }
2. 在Resolver中抛出自定义错误
替换原来的普通Error,抛出我们定义的HttpError:
// 示例:在某个查询/变更的Resolver中 throw new HttpError("Not Authorized.", 401);
3. 配置GraphQL中间件和响应拦截
通过Express中间件拦截GraphQL响应,根据错误中的状态码设置HTTP响应状态;同时在customFormatErrorFn中格式化错误信息,将状态码附加到响应体中:
// 第一步:添加响应拦截中间件,用于设置HTTP状态码 graphql_router.use("/", (req, res, next) => { // 保存原生的res.json方法 const originalJson = res.json; res.json = function(data) { // 如果响应体包含错误,取第一个错误的状态码设置HTTP状态 if (data.errors?.length > 0) { const statusCode = data.errors[0].extensions?.statusCode || 500; res.status(statusCode); } return originalJson.call(this, data); }; next(); }); // 第二步:配置GraphQL中间件 graphql_router.use("/", graphqlHTTP({ schema: schema, graphiql: process.env.NODE_ENV === 'development', contextValue: { ip: req.ip }, customFormatErrorFn: (error) => { const originalError = error.originalError; // 识别自定义的HttpError if (originalError instanceof HttpError) { return { message: originalError.message, extensions: { statusCode: originalError.statusCode } }; } // 其他未知错误默认返回500状态码 return { message: error.message, extensions: { statusCode: 500 } }; } }));
效果说明
- 后端抛出错误后,HTTP响应会带上对应的状态码(比如401、500等)
- 响应体的
errors数组中会包含错误信息和状态码,前端可以根据状态码或错误信息展示对应的本地化文本
内容的提问来源于stack exchange,提问作者Tarik Ulker
相关产品推荐
相关产品推荐

