@apollo/client useLazyQuery遇错误仍触发.then(),useMutation正常触发.catch()
问题原因及解决方案
这是Apollo Client(你使用的useLazyQuery/useMutation属于Apollo生态)对GraphQL查询和变更的错误处理逻辑差异导致的,核心原因在于GraphQL的响应特性和Apollo的设计倾向:
1. GraphQL响应的本质
不管是查询(Query)还是变更(Mutation),只要HTTP请求本身成功(状态码200),即使存在业务/权限错误,后端都会返回包含data(可能为null)和errors字段的JSON响应,而非HTTP错误状态码。
2. Apollo Client的处理差异
- useLazyQuery/useQuery:默认将GraphQL层面的错误(比如你遇到的权限不足)视为“可容忍”的情况——因为查询可能允许部分字段成功返回,所以Promise会正常resolve,错误被放在返回结果的
errors数组里,不会触发.catch()。只有当出现网络错误(比如HTTP 500、请求超时、跨域失败)时,才会触发.catch()。 - useMutation:默认将GraphQL错误视为“严重错误”——因为变更操作通常是原子性的(要么全成要么全败),所以当响应里存在
errors时,Apollo会主动将这些错误抛出,触发Promise的.catch()。
3. 解决方法
方法一:手动检查useLazyQuery的返回结果
在.then()回调里主动判断errors字段,处理业务错误:
const [getMe] = useLazyQuery(ME_QUERY); getMe() .then(result => { if (result.errors) { // 处理权限错误等业务逻辑错误 alert(result.errors[0].message); return; } // 处理正常返回的数据 console.log(result.data.me); }) .catch(networkError => { // 处理网络层面的错误 console.error('网络请求失败:', networkError); });
方法二:修改errorPolicy强制抛出错误
给useLazyQuery设置errorPolicy: 'none',让Apollo把GraphQL错误当作Promise reject的触发条件,这样就能在.catch()里统一处理所有错误:
const [getMe] = useLazyQuery(ME_QUERY, { errorPolicy: 'none' }); getMe() .then(result => { // 只有完全无错误时才会走到这里 console.log(result.data.me); }) .catch(error => { // 这里会捕获GraphQL错误和网络错误 console.error(error.message); });
方法三:手动抛出错误触发catch
在.then()里检测到errors时,主动抛出错误,让后续的.catch()处理:
getMe() .then(result => { if (result.errors) { throw new Error(result.errors[0].message); } return result.data; }) .then(data => { console.log(data.me); }) .catch(error => { console.error('错误:', error.message); });
内容的提问来源于stack exchange,提问作者Punkweb
相关产品推荐
相关产品推荐

