You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 16:54:55