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 + 请求取消,这套基本可以直接用于生产项目。

相关推荐
子兮曰5 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰5 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万5 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝5 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋5 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95275 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大5 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师5 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学5 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端