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 小时前
DeepSeek‑V4.1‑Flash‑1017完整解读:模型升级+Search/Fetch搜索API开放,Agent开发者要注意哪些坑
前端·网络·人工智能
原则猫9 小时前
UDP 到底怎么实现可靠的
前端
Java后端的Ai之路9 小时前
14、ReactJS - 路由(Router)
前端·react.js·状态模式
裕晟资质规划11 小时前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全
ShineWinsu11 小时前
对于JavaScript:JavaScript基础语法的解析
开发语言·前端·javascript·面试·web·基础语法·循环
月夏11 小时前
Vue3 转 React:18 项对照表 + 5 个必踩的坑(附 7 天上手路线)
前端
广州华水科技11 小时前
单北斗GNSS位移监测系统的应用与维护解析
前端
梦曦i12 小时前
uni-storage 0.1.0 发布:TTL过期管理+多实例隔离
前端·storage·uni-app x
猫头_13 小时前
AI 流式传输工程指南:模型吐出半截 JSON,前端如何边收边渲染?
前端·javascript·llm
console.log('npc')13 小时前
第 1 章 项目概述与环境搭建
前端·人工智能·大模型