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

如何在ReactJS应用中标准化API请求的错误处理

解决React中API错误处理重复冗余的方案

不用找复杂框架,自己封装一套复用逻辑就够了,既灵活又能适配你的API错误格式,还能避免到处改代码的麻烦。下面分两步来实现:

第一步:给Axios加全局错误拦截器

先统一处理所有API请求的错误,把各种格式的错误转换成标准化结构,这样组件里不用每次都解析error.response.data。

// src/utils/axios.js
import axios from 'axios';

const api = axios.create({
  baseURL: '你的API基础地址',
});

// 响应错误拦截器
api.interceptors.response.use(
  response => response,
  error => {
    let standardizedError = {
      type: 'UNKNOWN', // 默认类型
      generalMessages: [],
      fieldErrors: [],
    };

    // 1. API返回的错误(有response.data.error)
    if (error.response?.data?.error) {
      const errorPayload = error.response.data.error;
      standardizedError.type = 'API_ERROR';

      // 处理通用错误消息
      if (errorPayload.messages) {
        standardizedError.generalMessages = Array.isArray(errorPayload.messages) 
          ? errorPayload.messages 
          : [errorPayload.messages];
      }

      // 处理字段验证错误
      if (errorPayload.validationErrors) {
        standardizedError.fieldErrors = errorPayload.validationErrors.map(err => ({
          field: err.fieldName,
          message: err.message,
        }));
      }
    } 
    // 2. Axios生成的错误(超时、无响应、404/500等)
    else {
      standardizedError.type = 'NETWORK_ERROR';
      standardizedError.generalMessages = [error.message || '请求失败,请稍后重试'];
    }

    // 把标准化后的错误抛出去
    return Promise.reject(standardizedError);
  }
);

export default api;

第二步:封装自定义Hook处理请求状态和错误

把请求状态(加载中、成功、错误)、错误处理逻辑封装成Hook,不管是表单提交还是普通PATCH请求都能复用。

// src/hooks/useApiRequest.js
import { useState, useCallback } from 'react';
import { fieldNameTransformer } from '你的字段转换工具路径';

export const useApiRequest = (setError = null) => {
  const [requestStatus, setRequestStatus] = useState('input');
  const [generalRequestError, setGeneralRequestError] = useState(null);

  const handleRequest = useCallback(async (apiCall, onSuccess) => {
    if (requestStatus === 'requesting') return;
    
    setRequestStatus('requesting');
    setGeneralRequestError(null);

    try {
      const response = await apiCall();
      setRequestStatus('success');
      onSuccess?.(response);
    } catch (standardizedError) {
      // 区分错误类型处理UI状态
      if (standardizedError.type === 'API_ERROR' && standardizedError.fieldErrors.length > 0) {
        setRequestStatus('input');
      } else {
        setRequestStatus('error');
      }

      // 设置通用错误消息
      setGeneralRequestError(standardizedError.generalMessages);

      // 如果是表单场景,处理字段错误(依赖React Hook Form的setError)
      if (setError && standardizedError.fieldErrors.length > 0) {
        standardizedError.fieldErrors.forEach(err => {
          const transformedField = fieldNameTransformer(err.field);
          setError(transformedField, {
            type: 'server',
            message: err.message,
          });
        });
      }
    }
  }, [requestStatus, setError]);

  return {
    requestStatus,
    generalRequestError,
    handleRequest,
  };
};

在组件中使用示例

不管是表单提交还是普通更新请求,都能简化代码:

表单提交场景

import { useForm } from 'react-hook-form';
import api from '../utils/axios';
import { useApiRequest } from '../hooks/useApiRequest';
import { ACTIONS } from '../contexts/emailIntegrationContext';

const REQUEST_STATUS = {
  REQUESTING: 'requesting',
  INPUT: 'input',
  ERROR: 'error',
  SUCCESS: 'success',
};

const YourFormComponent = ({ appUserConnect, emailIntegrationContext }) => {
  const { register, handleSubmit, setError } = useForm();
  const { requestStatus, generalRequestError, handleRequest } = useApiRequest(setError);

  const onSubmit = handleSubmit(async (formData) => {
    await handleRequest(
      // 传入API调用函数
      () => api.patch('end_point_data', formData),
      // 成功后的回调
      (response) => {
        emailIntegrationContext.dispatch({
          type: ACTIONS.UPDATE,
          id: appUserConnect.appUserConnectId,
          payload: response.data.payload,
        });
      }
    );
  });

  return (
    // 你的表单UI,根据requestStatus显示加载状态,generalRequestError显示通用错误
    <form onSubmit={onSubmit}>
      {generalRequestError && <div className="error">{generalRequestError.join(', ')}</div>}
      {/* 表单输入项 */}
      <button type="submit" disabled={requestStatus === REQUEST_STATUS.REQUESTING}>
        {requestStatus === REQUEST_STATUS.REQUESTING ? '提交中...' : '提交'}
      </button>
    </form>
  );
};

普通更新请求场景(无表单)

import api from '../utils/axios';
import { useApiRequest } from '../hooks/useApiRequest';

const YourUpdateComponent = () => {
  const { requestStatus, generalRequestError, handleRequest } = useApiRequest();

  const handleUpdate = async () => {
    await handleRequest(
      () => api.patch('some_update_endpoint', { data: 'xxx' }),
      (response) => {
        // 成功后的UI更新逻辑
        console.log('更新成功', response.data);
      }
    );
  };

  return (
    <div>
      {generalRequestError && <div className="error">{generalRequestError.join(', ')}</div>}
      <button onClick={handleUpdate} disabled={requestStatus === 'requesting'}>
        {requestStatus === 'requesting' ? '更新中...' : '更新'}
      </button>
    </div>
  );
};

关于第三方库

如果不想自己写,React Query(现在叫TanStack Query)也能帮你处理请求状态和错误,但它更偏向数据缓存,如果你只是需要错误和状态管理,上面的自定义方案更轻量,也更贴合你的API格式。

内容的提问来源于stack exchange,提问作者Burton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:18:06