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

JavaScript/React生态调用后端API时的统一错误处理方案咨询

React Native 网络请求统一错误处理方案

你当前写法的核心冗余点在于:client层、接口定义层的try/catch没有实现任何实际处理逻辑,仅做了二次错误抛出,属于完全可以删除的无效代码。

你需要的类express中间件的能力,Axios本身已经通过拦截器提供,可以基于拦截器实现全链路通用错误统一处理,再配合可选的响应包装消除业务层的try/catch嵌套。


第一步:重构client.js,基于Axios拦截器实现统一错误处理

// client.js
import axios from 'axios';

// 1. 创建自定义Axios实例,统一配置基础参数
const apiClient = axios.create({
  baseURL: domain, // 直接配置基础域名,无需每次拼接
  timeout: 15000, // 统一配置超时时间
  // 其他通用配置如全局请求头都可以在此处定义
});

// 2. 请求拦截器:统一处理请求前逻辑,如加认证token、签名等
apiClient.interceptors.request.use(
  (config) => {
    // 示例:统一注入登录token
    const userToken = getTokenFromLocalStorage();
    if (userToken) config.headers.Authorization = `Bearer ${userToken}`;
    return config;
  },
  (error) => Promise.reject(error)
);

// 3. 响应拦截器:核心统一错误处理逻辑,对应你需要的express中间件能力
apiClient.interceptors.response.use(
  // 请求成功直接返回响应数据,后续层级无需重复取`.data`
  (response) => response.data,
  (error) => {
    // 此处统一处理所有通用错误,无需业务层重复实现
    if (error.response) {
      // 服务端返回错误状态码
      const { status, data } = error.response;
      switch (status) {
        case 401:
          // 统一处理未授权:清空用户信息、跳登录页、全局提示
          clearUserStorage();
          navigation.navigate('Login');
          showToast('登录状态已过期,请重新登录');
          break;
        case 403:
          showToast('你没有权限执行该操作');
          break;
        case 500:
          showToast('服务器异常,请稍后重试');
          break;
        default:
          // 优先使用服务端返回的错误提示
          showToast(data?.message || '请求失败,请稍后重试');
      }
    } else if (error.request) {
      // 请求发出未收到响应:网络异常、服务端不可用等
      showToast('网络异常,请检查网络连接后重试');
    } else {
      // 请求配置错误
      showToast('请求参数异常,请重试');
    }

    // 若有需要业务层特殊处理的错误,此处继续抛出即可,无需特殊处理可直接return undefined
    return Promise.reject(error);
  }
);

// 封装请求方法,无需多余try/catch
export const get = (endpoint, config = {}) => apiClient.get(endpoint, config);
export const post = (endpoint, data = {}, config = {}) => apiClient.post(endpoint, data, config);
// 同理可封装put、delete等方法

第二步:简化接口定义层代码,删除冗余try/catch

// posts.js
import { get } from './client';

const getPosts = async (userID, page, pageSize) => {
  // 使用axios自带的params配置,无需手动拼接query字符串,避免编码问题
  return get(endpoint, { params: { userID, page, pageSize } });
};

第三步:业务层调用的两种可选写法

写法1:仅需特殊处理错误时保留try/catch

普通场景下通用错误已经在拦截器处理完成,不需要额外加try/catch,只有该接口需要做特殊错误逻辑时才添加:

const loadPosts = async () => {
  try {
    const data = await getPosts(1, 1, 10);
    // 直接拿到服务端返回的业务数据,无需再取`.data`
    setPosts(data);
  } catch (error) {
    // 仅写该接口专属的错误处理逻辑,比如自定义错误提示展示位置
    setListError('帖子加载失败,请下拉刷新重试');
  }
};

写法2:用元组包装完全消除try/catch

如果不想写try/catch,可以封装一个通用请求包装函数,返回类似Go语言的[数据, 错误]元组:

// 在client.js中添加通用包装方法
export const withError = async (requestPromise) => {
  try {
    const data = await requestPromise;
    return [data, null];
  } catch (error) {
    return [null, error];
  }
};

业务层调用:

const loadPosts = async () => {
  const [data, error] = await withError(getPosts(1, 1, 10));
  if (error) {
    setListError('帖子加载失败,请下拉刷新重试');
    return;
  }
  setPosts(data);
};

额外优化建议

如果需要进一步简化加载状态、缓存、重试等逻辑,可以引入React Query/SWR这类数据请求库,全局错误处理也可以通过库的配置统一实现,无需自己维护loading、error等组件状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 18:30:04