# react-native-fetch-xhr **Repository Path**: ws18250840411/react-native-fetch-xhr ## Basic Information - **Project Name**: react-native-fetch-xhr - **Description**: 兼容fetch自动降解xhr的请求库 - **Primary Language**: Unknown - **License**: ISC - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-12 - **Last Updated**: 2026-02-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # react-native-fetch-xhr 一个极致精简、高性能的跨平台 HTTP 请求库,专为 React Native (iOS/Android) 和 Web 环境设计。 **单文件 ~300 行 TypeScript,ESM ~23 KB / gzip ~9 KB,零运行时依赖。** 它提供了一套统一的 API(与主流 HTTP 客户端一致),在支持 `fetch` 的环境中优先使用 fetch,在不支持的环境或特殊场景下自动降级为 `XMLHttpRequest`。 ## 📊 体积对比 | 库 | min 体积 | gzip 体积 | 运行时依赖 | |----|----------|-----------|------------| | **react-native-fetch-xhr** | **~23 KB** | **~9 KB** | **0** | | axios | ~55 KB | ~14 KB | 0(但含 Node 适配器) | | ky | ~22 KB | ~8 KB | 0(仅 fetch,无 XHR 降级) | > 与 axios 功能覆盖度接近(拦截器、取消、超时、FormData、参数序列化),但不含 Node.js 专属代码,体积更小,且针对 RN + Web 场景做了专项优化。 ## ✨ 特性 - **三端统一**:一套代码同时运行在 React Native (iOS/Android) 和 Web 浏览器中 - **极致精简**:单文件实现,零运行时依赖,gzip 后仅 ~9 KB - **fetch 优先 + 自动降级 XHR**:默认使用现代 `fetch`,必要时自动切换到 `XMLHttpRequest` - **完整的类型安全**:100% TypeScript 编写,提供完整的 `.d.ts` 类型定义 - **高性能设计**: - 拦截器链路优化,减少不必要的 Promise 创建 - XHR 适配器自动将 header 转为 Title-Case 避免兼容性问题 - 请求/响应 transformer 延迟求值,零开销默认路径 - **功能丰富**: - 拦截器(请求/响应),支持同步与异步模式 - `baseURL` + `params` 自动拼接与序列化 - `paramsSerializer` 自定义参数序列化 - `timeout` 超时设置 - `AbortSignal` / `CancelToken` 双重取消机制 - 自动处理 JSON 请求体和响应体 - 自动处理 `FormData` 文件上传 - `application/x-www-form-urlencoded` 自动编码 - `transformRequest` / `transformResponse` 自定义数据转换 - Web XSRF 防护(仅标准浏览器环境) - `fetchOptions` 透传到底层 `fetch` - `parseReviver` 自定义 JSON 解析 - `HttpStatusCode` 双向状态码映射 - **统一错误处理**:`CrossFetchError` 带标准化错误码(`ERR_NETWORK` / `ERR_CANCELED` / `ECONNABORTED` 等) ## ✅ 为什么选择这个库 | 需求 | react-native-fetch-xhr | axios | ky | |------|------------------------|-------|----| | RN iOS/Android + Web 三端统一 | ✅ | ⚠️ 含 Node 冗余代码 | ⚠️ 仅 fetch | | fetch 优先 + XHR 降级 | ✅ | ✅ | ❌ 仅 fetch | | 拦截器 | ✅ | ✅ | ✅ hooks | | 取消请求 (AbortSignal + CancelToken) | ✅ | ✅ | ✅ 仅 AbortSignal | | 零运行时依赖 | ✅ | ✅ | ✅ | | gzip < 10KB | ✅ ~9KB | ❌ ~14KB | ✅ ~8KB | | 完整 TypeScript 类型 | ✅ | ✅ | ✅ | **核心优势**: - **只做必需能力**:保留拦截器、参数/请求体序列化、响应解析、取消/超时、统一错误与响应结构;不引入与 RN/Web 无关的重功能 - **0 运行时依赖**:减少依赖冲突与体积负担,适合对启动性能、包体、升级风险更敏感的 RN 项目 - **迁移成本低**:API 与 axios 一致(`create/request/get/post/interceptors/defaults`),轻松迁移 ## ⚠️ 不适用场景 - 你强依赖上传/下载进度(`onUploadProgress` / `onDownloadProgress`) - 你需要 Node.js 专属能力(如 `http/https` adapter、`agent`、代理、cookie jar 等) - 你想要开箱即用的重策略能力(如重试、缓存、请求队列等;可以用拦截器自行实现) ## 📦 安装 ```bash npm install react-native-fetch-xhr ``` ```bash yarn add react-native-fetch-xhr ``` ## 🚀 快速上手 ### 基础请求 ```typescript import crossFetch from 'react-native-fetch-xhr'; // GET const res = await crossFetch.get('https://api.example.com/user', { params: { id: 12345 } }); console.log(res.data); // POST await crossFetch.post('https://api.example.com/user', { firstName: 'Fred', lastName: 'Flintstone' }); ``` ### 创建实例 ```typescript const api = crossFetch.create({ baseURL: 'https://api.example.com/v1', timeout: 10000, headers: { 'X-Custom-Header': 'foobar' } }); await api.get('/users'); ``` ### 兼容双参数写法 ```ts await crossFetch.request('https://api.example.com/user', { method: 'get' }); ``` ## 📖 详细使用指南 ### 拦截器 ```typescript // 请求拦截器 — 注入 Token api.interceptors.request.use((config) => { config.headers = { ...config.headers, Authorization: `Bearer ${getToken()}` }; return config; }); // 响应拦截器 — 统一处理 401 api.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { console.log('未授权,请登录'); } return Promise.reject(error); } ); ``` ### TypeScript 泛型 ```typescript interface User { id: number; name: string; email: string; } const res = await api.get('/user/1'); console.log(res.data.name); // 类型安全 ``` ### 错误处理 ```typescript import { isCrossFetchError } from 'react-native-fetch-xhr'; try { await api.get('/user/12345'); } catch (error) { if (isCrossFetchError(error)) { if (error.code === 'ECONNABORTED') console.log('请求超时'); else if (error.code === 'ERR_NETWORK') console.log('网络错误'); else if (error.response) { console.log('状态码:', error.response.status); console.log('响应数据:', error.response.data); } } } ``` ### 取消请求 ```typescript // 方式一:AbortController(推荐) const controller = new AbortController(); api.get('/data', { signal: controller.signal }); controller.abort(); // 方式二:CancelToken const { token, cancel } = crossFetch.CancelToken.source(); api.get('/data', { cancelToken: token }); cancel('不再需要'); ``` ### 文件上传 ```typescript const formData = new FormData(); formData.append('file', fileObject); formData.append('userId', '123'); // Content-Type 会自动处理,无需手动设置 await api.post('/upload', formData); ``` ### 自定义请求/响应转换 ```typescript const api = crossFetch.create({ transformRequest: [(data, headers) => { // 在请求发出前修改数据 return JSON.stringify(data); }], transformResponse: [(data) => { // 在响应到达前修改数据 const parsed = JSON.parse(data); return parsed.result; }], }); ``` ## 📦 响应结构 ```ts { data, // 响应数据(自动 JSON 解析) status, // HTTP 状态码 statusText, // 状态文本 headers, // CrossFetchHeaders 实例 config, // 请求配置 request // fetch: Request | xhr: XMLHttpRequest } ``` ## ⚙️ 请求配置 ```typescript { url: '/user', // 请求路径(必填) method: 'get', // 请求方法,默认 'get' baseURL: 'https://api.example.com/', // 基础 URL,自动拼接 headers: {}, // 请求头 params: { ID: 12345 }, // URL 查询参数 paramsSerializer: { serialize(p) {} }, // 自定义参数序列化 data: { key: 'value' }, // 请求体(POST/PUT/PATCH/DELETE) timeout: 10000, // 超时时间(ms),默认 0(无超时) adapter: 'fetch', // 强制指定适配器:'fetch' | 'xhr' responseType: 'json', // 响应类型:json | text | blob | arraybuffer | stream | formdata withCredentials: false, // 跨域携带凭证 signal: controller.signal, // AbortSignal 取消 cancelToken: token, // CancelToken 取消 validateStatus: (s) => s >= 200 && s < 300, // 自定义状态码校验(默认值) transformRequest: [(data, headers) => data], // 请求数据转换 transformResponse: [(data, headers, status) => data], // 响应数据转换 fetchOptions: {}, // 透传到底层 fetch(redirect/mode/cache 等) xsrfCookieName: 'XSRF-TOKEN', // XSRF cookie 名称 xsrfHeaderName: 'X-XSRF-TOKEN', // XSRF header 名称 withXSRFToken: false, // 强制注入 XSRF token(跨域时需设为 true) formSerializer: {}, // FormData 序列化选项 transitional: { // 过渡选项 silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false, }, parseReviver: (key, val) => val, // JSON.parse reviver env: { fetch, XMLHttpRequest }, // 自定义环境注入 } ``` ## 🔧 导出一览 ```typescript import crossFetch, { CrossFetchError, CrossFetchHeaders, CanceledError, CancelToken, isCrossFetchError, isCancel, mergeConfig, getAdapter, toFormData, formToJSON, HttpStatusCode, VERSION, all, spread, } from 'react-native-fetch-xhr'; ``` ## 📝 License ISC