Next.js/React中GraphQL更新用户名的运行时错误处理问询
问题分析与解决方案
为什么已用try/catch仍出现Bad Request错误?
你在catch块中抛出的UserInputError会被Apollo Server默认识别为客户端输入错误,自动返回HTTP 400 Bad Request状态码,这是框架的预期行为。但如果出现未捕获的运行时错误,大概率是你的catch块没有覆盖所有异常场景——比如非Prisma已知请求错误的异常没被处理,导致抛出后未被捕获。
而直接返回e会触发类型不匹配错误,是因为你的GraphQL TypeDef定义updateName返回String,但实际返回的是Prisma错误对象,不符合类型约定,所以GraphQL会抛出"Invalid invocation"错误。
正确处理方式
方案1:定义结构化返回类型(推荐)
通过自定义GraphQL类型,让接口返回包含成功状态、消息和数据的结构,避免类型不匹配,同时更友好地传递错误信息。
调整TypeDef
# 自定义返回结果类型 type UpdateNameResult { success: Boolean! message: String name: String } type Mutation { updateName(id: ID!, newName: String!): UpdateNameResult! }
修正Resolver代码
async function updateName(parent, { id, newName }, context) { try { const user = await context.prisma.user.update({ where: { id }, data: { name: newName }, }); return { success: true, name: user.name, message: "用户名更新成功" }; } catch (e) { // 处理Prisma唯一约束冲突(用户名已存在) if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") { return { success: false, message: "该用户名已存在,请更换其他名称" }; } // 处理其他未知错误 return { success: false, message: `更新失败:${e.message}` }; } }
前端代码调整
const UPDATE_NAME = gql` mutation Mutation($id: ID!, $newName: String!) { updateName(id: $id, newName: $newName) { success message name } } `; const [updateName, { data, loading, error }] = useMutation(UPDATE_NAME); // 调用更新方法示例 const handleUpdateUsername = async (userId, newName) => { const result = await updateName({ variables: { id: userId, newName } }); const { success, message, name } = result.data.updateName; if (success) { // 执行成功逻辑,比如更新本地状态 } else { // 显示错误提示,比如弹窗展示message } }; return ( <> {loading && <span>更新中...</span>} {error && <span>请求异常:{error.message}</span>} {data && ( data.updateName.success ? <span>更新成功!新用户名:{data.updateName.name}</span> : <span>更新失败:{data.updateName.message}</span> )} </> );
方案2:使用Apollo错误类型抛出异常
如果你更倾向于通过抛出错误的方式处理,需确保使用Apollo官方提供的错误类型,让前端能通过useMutation的error参数正确捕获。
修正Resolver代码
const { UserInputError } = require('apollo-server-express'); // 根据你的项目环境导入 async function updateName(parent, { id, newName }, context) { try { const user = await context.prisma.user.update({ where: { id }, data: { name: newName }, }); return user.name; } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") { // 抛出Apollo用户输入错误,前端可通过error参数捕获 throw new UserInputError("该用户名已存在", { invalidArgs: { newName } }); } // 其他错误统一抛出 throw new Error(`更新失败:${e.message}`); } }
前端错误处理
// 直接通过useMutation返回的error参数处理 return ( <> {loading && <span>更新中...</span>} {error && <span>更新失败:{error.message}</span>} {data && <span>更新成功!新用户名:{data.updateName}</span>} </> );
内容的提问来源于stack exchange,提问作者user3226932
相关产品推荐
相关产品推荐

