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

相关推荐
学习星球1 小时前
Vue 3 实战:拆解 RealWorld 项目
前端·vue.js
铁皮饭盒1 小时前
网页端, 6.5MB人脸识别模型, 谷歌框架, 又快又准
前端·javascript·后端
xiaohaiAIgeo1 小时前
【2026年】ASHRAE 110与EN 14175通风柜测试标准对比:进口与国产品牌性能差距
java·前端·数据库·科普知识
用户2930750976692 小时前
TypeScript 必考题:Type 与 Interface 全面对比
前端
hunterandroid2 小时前
[鸿蒙从零到一] HarmonyOS 媒体能力实战:图片、音频与视频处理
前端
打呵欠的猫2 小时前
我让 AI 封装了一个 ImageUpload 组件,它设计的 5 层校验链路比我想的周全
前端·ai编程
AlexMaybeBot2 小时前
躺在沙发上开发 Openclaw 的移动端APP
前端·flutter
用户2181697049302 小时前
Flutter(十三)Text Image TextField
前端
程序员黑豆2 小时前
深入解析Java数据类型:基本类型与引用类型的本质区别与实战选择
前端·ai编程·全栈