RN 网络请求:Fetch / Axios 封装、超时、拦截器

如果你是在做 React Native 网络层封装 ,比较推荐把 Fetch / Axios、超时、请求/响应拦截、统一错误处理、Token 刷新这些能力集中到一个 request 层,而不是散落在业务代码里。

1. Fetch vs Axios

能力 Fetch Axios
RN 原生支持 需要安装
超时 ❌ 需要自己实现 timeout
请求拦截器
响应拦截器
JSON 处理 手动 response.json() 自动
HTTP 错误处理 4xx/5xx 不自动 reject 默认 reject
Token 注入 手动 拦截器
Token 刷新 手动实现 拦截器中实现
取消请求 AbortController AbortController
复杂项目 ⭐⭐⭐ ⭐⭐⭐⭐⭐

如果是中大型 RN 项目,我更推荐 Axios。


2. Axios 基础封装

安装:

复制代码
npm install axios

例如:

css 复制代码
src/
├── api/
│   ├── client.ts
│   ├── user.ts
│   └── index.ts
├── storage/
│   └── token.ts
└── types/
    └── api.ts

client.ts

php 复制代码
import axios from 'axios';

export const http = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 15_000,
  headers: {
    'Content-Type': 'application/json',
  },
});

业务层:

typescript 复制代码
import { http } from './client';

export const getUser = (id: string) => {
  return http.get(`/users/${id}`);
};

这样业务代码不需要关心 Axios 配置。


3. 请求拦截器

最常见的用途是自动加入 Token。

ini 复制代码
http.interceptors.request.use(
  async config => {
    const token = await getAccessToken();

    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }

    return config;
  },
  error => {
    return Promise.reject(error);
  },
);

于是:

csharp 复制代码
http.get('/profile');

实际发送:

sql 复制代码
GET /profile
Authorization: Bearer xxxxx

业务层不需要每次手动传 Token。


4. 响应拦截器

建议统一处理 HTTP 错误:

go 复制代码
http.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    if (error.response) {
      const { status } = error.response;

      switch (status) {
        case 401:
          // Token 失效
          break;

        case 403:
          // 无权限
          break;

        case 404:
          // API 不存在
          break;

        case 500:
          // 服务端错误
          break;
      }
    } else if (error.request) {
      // 请求发出,但没有收到响应
    } else {
      // 请求配置阶段发生错误
    }

    return Promise.reject(error);
  },
);

这里建议不要直接在拦截器里 Toast 所有错误

例如:

dart 复制代码
// ❌ 不推荐
Toast.show('请求失败');

因为有些接口的错误应该由页面自己处理。

更好的方式是:

arduino 复制代码
throw new ApiError(...)

然后由业务层决定 UI 怎么表现。


5. Fetch 如何实现超时

Fetch 最大的问题之一就是没有 Axios 那么方便的 timeout

现代 RN 可以使用 AbortController

javascript 复制代码
export async function request(
  url: string,
  options: RequestInit = {},
  timeout = 15000,
) {
  const controller = new AbortController();

  const timer = setTimeout(() => {
    controller.abort();
  }, timeout);

  try {
    const response = await fetch(url, {
      ...options,
      signal: controller.signal,
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    return await response.json();
  } finally {
    clearTimeout(timer);
  }
}

调用:

ini 复制代码
const user = await request('/users/123');

15 秒没有完成,就会触发 abort()


6. Axios 超时更简单

Axios:

ini 复制代码
const http = axios.create({
  baseURL: API_URL,
  timeout: 15000,
});

超时后:

lua 复制代码
if (axios.isAxiosError(error)) {
  if (error.code === 'ECONNABORTED') {
    console.log('请求超时');
  }
}

因此 Axios 在这一点上明显更省事。


7. 真正项目里最重要的是 Token 刷新

例如:

css 复制代码
请求 A ──→ 401
请求 B ──→ 401
请求 C ──→ 401
             ↓
        refresh token
             ↓
        新 access token
             ↓
   A / B / C 重新请求

不要让 A、B、C 同时刷新 Token。

应该做成:

typescript 复制代码
let isRefreshing = false;

let pendingRequests: Array<{
  resolve: (token: string) => void;
  reject: (error: unknown) => void;
}> = [];

第一个请求负责 refresh:

ini 复制代码
if (!isRefreshing) {
  isRefreshing = true;

  try {
    const token = await refreshToken();

    pendingRequests.forEach(item => {
      item.resolve(token);
    });

    pendingRequests = [];
  } catch (error) {
    pendingRequests.forEach(item => {
      item.reject(error);
    });

    pendingRequests = [];
  } finally {
    isRefreshing = false;
  }
}

后面的请求进入队列等待。

这是 RN Axios 封装里非常值得单独设计的一块


8. 推荐的最终架构

我比较推荐:

vbscript 复制代码
UI / Screen
     │
     ▼
  React Query
     │
     ▼
 API Service
     │
     ▼
 Axios Client
     │
     ├── Request Interceptor
     │      └── Access Token
     │
     ├── Response Interceptor
     │      ├── 统一错误
     │      ├── 401
     │      └── Token Refresh
     │
     └── Timeout

例如:

csharp 复制代码
// user.ts

export async function getUser() {
  const { data } = await http.get<User>('/user');
  return data;
}

页面:

php 复制代码
const { data, isLoading, error } = useQuery({
  queryKey: ['user'],
  queryFn: getUser,
});

这样就形成了:

UI 不关心 Axios,API 不关心 Token,Axios 不关心页面 UI。

这是比较干净的 RN 网络层分层方式。

如果你的项目是 RN + TypeScript + React Query ,我建议直接做成一个完整的 Axios Client超时 + Token 注入 + 401 自动刷新 + 并发请求队列 + 统一 ApiError + 请求取消,这套基本可以直接用于生产项目。

相关推荐
星栈6 小时前
自定义 UI-UX-Pro-Max 的 CSV 知识库,把 AI 生成的后台拉回行业该有的样子
前端·agent·weui
研☆香6 小时前
简单的图片上传 删除 预览
前端
ITresearchGuest6 小时前
我用 AI 一小时写了一个世界杯数据可视化平台|前端 VibeCoding 初体验
前端·人工智能·信息可视化
慧一居士7 小时前
Vite项目中使用Less步骤,详细使用示例
前端·css
花间相见8 小时前
【LangChain组件03】—— LangChain Agents 执行与状态:工作流程与状态管理实战
java·前端·langchain
kyriewen8 小时前
面试官让我用 AI 重构一个 8 年陈的 React 组件——他说他不看代码,只看我会不会拆
前端·javascript·面试
计算机魔术师8 小时前
700吉瓦「幽灵用电」:美国AI数据中心的抢电闹剧正在失控
前端
IT_陈寒8 小时前
JavaScript数组排序踩的坑,差点让我加班到凌晨
前端·人工智能·后端
风骏时光牛马8 小时前
提示词工程:大模型交互的核心构建艺术
前端
今日无bug9 小时前
大模型的回答是怎么一个字一个字蹦出来的?前端流式输出解析
前端·llm·agent