React Query + Next.js13路由处理器:如何避免Axios错误日志刷屏
问题描述
我正在开发一个小型应用,需要在用户注册前检查邮箱是否已注册,若已注册则返回错误。后端route.ts中返回对应响应:注册成功返回200状态码,邮箱已存在返回409状态码。添加用户功能正常,但重复添加同一用户时,尽管已在useMutation的onError中捕获409错误并显示toast通知,控制台仍会被Axios的409错误日志刷屏,请问该问题的原因是什么,如何解决?
相关代码
const form = useForm<z.infer<typeof UserValidator>>({ resolver: zodResolver(UserValidator), defaultValues: { website: "", email: "", }, }) const {mutate: createUser, error, isLoading} = useMutation({ mutationFn: () => {return axios.post('/api/user', form.getValues()).then(res => res.data)}, onError: (err) => { if(err instanceof AxiosError){ if(err.response?.status === 409){ return toast({ title: "该邮箱已被注册", description: "请选择其他邮箱", variant: "destructive" }) } } }, onSuccess: (data) => { console.log("注册成功") } }) const onSubmit = () => { createUser() } return( <> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className={`space-y-8 ${showForm ? 'visible' : 'hidden'}`}> <div className="flex"> <FormField control={form.control} name="email" render={({ field }) => ( <FormItem> <FormLabel>邮箱</FormLabel> <FormControl> <Input placeholder="邮箱" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="website" render={({ field }) => ( <FormItem> <FormLabel>网站</FormLabel> <FormControl> <Input placeholder="网站" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> </div> <Button type="submit" isLoading={isLoading}>提交</Button> </form> </Form> </> )
原因分析
Axios默认会将所有非2xx的HTTP状态码(比如409)包装成AxiosError并抛出异常。尽管你在useMutation的onError中处理了这个错误,但该异常在Promise链中未被完全拦截时,浏览器的全局错误处理机制仍会将其打印到控制台。useMutation的onError仅负责业务层面的错误处理,无法阻止异常本身被浏览器记录。
解决方案
方案一:在mutationFn中精准捕获409错误
修改mutationFn,用try/catch包裹请求,仅将非409的错误重新抛出,既保留onError的业务处理逻辑,又避免409错误被控制台打印:
mutationFn: async () => { try { const res = await axios.post('/api/user', form.getValues()); return res.data; } catch (err) { if (err instanceof AxiosError) { // 仅在非409状态时重新抛出错误,交给onError处理其他异常 if (err.response?.status !== 409) { throw err; } // 409错误手动reject,触发onError的业务提示 return Promise.reject(err); } // 非Axios错误直接抛出 throw err; } },
方案二:通过Axios响应拦截器处理409错误
在Axios全局配置中添加响应拦截器,将409状态的错误转换为成功Promise,避免抛出异常,之后在useMutation中判断响应状态处理逻辑:
// 配置Axios全局响应拦截器 axios.interceptors.response.use( (response) => response, (error) => { if (error instanceof AxiosError && error.response?.status === 409) { // 将409错误转为resolved Promise,阻止异常抛出 return Promise.resolve(error.response); } return Promise.reject(error); } ); // 修改useMutation逻辑 const {mutate: createUser, error, isLoading} = useMutation({ mutationFn: async () => { const res = await axios.post('/api/user', form.getValues()); // 若为409状态,手动reject触发onError的提示 if (res.status === 409) { return Promise.reject(new AxiosError('邮箱已存在', undefined, undefined, undefined, res)); } return res.data; }, // 原有onError逻辑保持不变 });
方案三:禁用React Query的错误自动抛出(谨慎使用)
如果错误日志来自React Query的默认打印,可以在useMutation配置中添加throwOnError: false,但这会影响所有错误的抛出行为,需根据业务场景选择:
const {mutate: createUser, error, isLoading} = useMutation({ mutationFn: () => axios.post('/api/user', form.getValues()).then(res => res.data), throwOnError: false, // 阻止React Query自动抛出错误 onError: (err) => { // 原有处理逻辑不变 }, });
内容的提问来源于stack exchange,提问作者StackMyFlow
相关产品推荐
相关产品推荐

