RNOH Bundle中集成 Axios 网络请求实战:呈现 GitCode 用户信息展示
本文详细介绍了在React Native + 开源鸿蒙项目中集成Axios库实现网络请求功能的过程。文章从技术选型出发,对比了Axios相较于原生fetch API的优势,包括自动JSON转换、请求超时/取消、拦截器支持等特性。通过分步骤指南,展示了如何安装配置Axios,设计项目目录结构,并实现API接口层、错误处理机制和自定义Hook。其中重点讲解了类型安全定义、请求函数实现、完善的错误分类处
📚 目录
ℹ️ 说明:
axios三方库在适配开源鸿蒙过程不涉及代码修改,可直接引入。
🎯 目标与背景
📌 项目需求
在 React Native + 开源鸿蒙项目中,需要集成 Axios 库来实现网络请求功能,并通过 GitCode API 获取并展示用户信息。
🧰 技术选型
- Axios: 基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js
- 优势:
- 自动转换 JSON 数据
- 请求/响应拦截器
- 取消请求
- 超时处理
- 更好的错误处理机制
- 支持 TypeScript
🔗 API 接口
- 接口地址:
https://api.gitcode.com/api/v5/users/{username} - 请求方法: GET
- 返回格式: JSON
- 示例:
https://api.gitcode.com/api/v5/users/CodexBai
⚡️ Axios 简介与优势
为什么选择 Axios?
相比 React Native 原生的 fetch API,Axios 提供了更丰富的功能和更好的开发体验:
| 特性 | Fetch | Axios |
|---|---|---|
| 自动 JSON 转换 | ❌ 需要手动调用 .json() |
✅ 自动转换 |
| 请求超时 | ❌ 需要手动实现 | ✅ 内置支持 |
| 请求取消 | ⚠️ 需要 AbortController | ✅ 内置支持 |
| 拦截器 | ❌ 不支持 | ✅ 支持请求/响应拦截 |
| 错误处理 | ⚠️ 需要手动检查状态码 | ✅ 自动处理 HTTP 错误 |
| TypeScript 支持 | ⚠️ 需要额外类型定义 | ✅ 原生支持 |
| 请求/响应数据转换 | ❌ 不支持 | ✅ 支持 |
🛠️ 安装与配置
📦 使用 npm 安装
在RNOH Bundle工程根目录打开终端,执行以下命令安装axios。
npm install axios@1.6.7
ℹ️ 说明:
@1.6.7为指定安装版本。


🧩 项目集成步骤
🗂️ 目录结构
在 bundles/ 目录下创建新的模块 gitcodeProfile/:
bundles/
└── gitcodeProfile/
├── api.ts # API 接口定义和请求函数
├── hooks.ts # 自定义 Hook(数据获取逻辑)
├── screen.tsx # UI 组件(用户信息展示)
└── index.ts # 模块导出
🔧 集成到主应用
- 更新
bundles/tabs.ts:添加新的 Tab 项 - 更新
App.tsx:扩展 TabKey 类型
🧠 代码实现详解
1️⃣ API 接口层 (api.ts)
✍️ 类型定义
export interface GitCodeUser {
id: number;
login: string;
name: string;
email?: string;
avatar_url?: string;
bio?: string;
blog?: string;
company?: string;
location?: string;
public_repos?: number;
public_gists?: number;
followers?: number;
following?: number;
created_at?: string;
updated_at?: string;
}
📝 设计要点:
- 使用
?标记可选字段,因为 API 可能不返回所有字段 - 明确的类型定义有助于 TypeScript 类型检查和 IDE 自动补全
📨 请求函数实现
import axios, { AxiosResponse } from 'axios';
export async function fetchGitCodeUser(username: string = 'CodexBai'): Promise<GitCodeUser> {
try {
const url = `https://api.gitcode.com/api/v5/users/${username}`;
const response: AxiosResponse<GitCodeUser> = await axios.get(url, {
timeout: 10000, // 10秒超时
headers: {
'Accept': 'application/json',
'User-Agent': 'DailyHotBundle/1.0',
},
});
return response.data;
} catch (error) {
// 错误处理逻辑(见下文)
}
}
🔧 关键配置说明:
- timeout: 设置请求超时时间为 10 秒,避免长时间等待
- headers:
Accept: 指定期望的响应格式User-Agent: 标识客户端应用
- 类型泛型:
AxiosResponse<GitCodeUser>确保响应数据的类型安全
2️⃣ 错误处理详解
Axios 的错误处理比 fetch 更加完善:
catch (error) {
if (axios.isAxiosError(error)) {
// Axios 错误(网络错误、HTTP 错误等)
if (error.response) {
// 服务器返回了错误状态码(4xx, 5xx)
throw new Error(
`请求失败: ${error.response.status} - ${error.response.statusText}`
);
} else if (error.request) {
// 请求已发出但没有收到响应(网络问题)
throw new Error('网络请求失败,请检查网络连接');
} else {
// 请求配置错误
throw new Error(`请求配置错误: ${error.message}`);
}
} else {
// 非 Axios 错误
throw new Error(`未知错误: ${String(error)}`);
}
}
📚 错误类型说明:
| 错误类型 | 触发条件 | 处理方式 |
|---|---|---|
error.response |
服务器返回 4xx/5xx | 显示 HTTP 状态码和错误信息 |
error.request |
网络连接失败 | 提示用户检查网络 |
| 其他错误 | 配置错误等 | 显示通用错误信息 |
3️⃣ 自定义 Hook (hooks.ts)
🔄 实现数据获取逻辑
import { useEffect, useState } from 'react';
import { fetchGitCodeUser, GitCodeUser } from './api';
export function useGitCodeUser(username: string = 'CodexBai') {
const [data, setData] = useState<GitCodeUser | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const fetchData = async () => {
let mounted = true;
setLoading(true);
setError(null);
try {
const userData = await fetchGitCodeUser(username);
if (mounted) {
setData(userData);
}
} catch (e) {
if (mounted) {
setError(String(e instanceof Error ? e.message : e));
}
} finally {
if (mounted) {
setLoading(false);
}
}
};
useEffect(() => {
fetchData();
return () => {
// 清理函数:防止组件卸载后更新状态
};
}, [username]);
return { data, loading, error, refetch: fetchData };
}
📝 设计要点:
-
状态管理:
data: 存储用户数据loading: 加载状态error: 错误信息
-
内存泄漏防护:
- 使用
mounted标志防止组件卸载后更新状态 - 在
useEffect的清理函数中重置标志
- 使用
-
暴露 refetch 方法:
- 允许外部手动触发数据刷新
- 支持下拉刷新等交互
4️⃣ UI 组件实现 (screen.tsx)
⭐ 核心功能
- 加载状态展示
- 错误处理与重试
- 用户信息展示
- 下拉刷新
🧷 关键代码片段
export function GitCodeProfileScreen() {
const { data, loading, error, refetch } = useGitCodeUser('CodexBai');
const [refreshing, setRefreshing] = React.useState(false);
const onRefresh = React.useCallback(async () => {
setRefreshing(true);
await refetch();
setRefreshing(false);
}, [refetch]);
// 加载中状态
if (loading && !data) {
return (
<View style={styles.centerContainer}>
<ActivityIndicator size="large" color="#007AFF" />
<Text style={styles.loadingText}>加载中...</Text>
</View>
);
}
// 错误状态
if (error) {
return (
<ScrollView
contentContainerStyle={styles.centerContainer}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
>
<Text style={styles.errorText}>❌ 加载失败</Text>
<Text style={styles.errorDetail}>{error}</Text>
<Pressable style={styles.retryButton} onPress={onRefresh}>
<Text style={styles.retryButtonText}>重试</Text>
</Pressable>
</ScrollView>
);
}
// 数据展示
return (
<ScrollView
style={styles.container}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
>
{/* 用户信息展示 */}
</ScrollView>
);
}
🚨 错误处理与异常管理
🌐 网络错误处理
// 在 api.ts 中
catch (error) {
if (axios.isAxiosError(error)) {
if (error.code === 'ECONNABORTED') {
throw new Error('请求超时,请稍后重试');
} else if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
throw new Error('无法连接到服务器,请检查网络');
}
// ... 其他错误处理
}
}
🔢 HTTP 状态码处理
if (error.response) {
switch (error.response.status) {
case 404:
throw new Error('用户不存在');
case 403:
throw new Error('访问被拒绝');
case 500:
throw new Error('服务器错误,请稍后重试');
default:
throw new Error(`请求失败: ${error.response.status}`);
}
}
🙂 用户友好的错误提示
在 UI 层展示错误时,使用友好的提示信息:
<Text style={styles.errorText}>❌ 加载失败</Text>
<Text style={styles.errorDetail}>{error}</Text>
<Pressable style={styles.retryButton} onPress={onRefresh}>
<Text style={styles.retryButtonText}>重试</Text>
</Pressable>
🪝 自定义 Hook 封装
🧱 Hook 设计模式
自定义 Hook 的优势:
- 逻辑复用: 多个组件可以共享数据获取逻辑
- 关注点分离: UI 组件专注于展示,Hook 处理数据逻辑
- 易于测试: 可以单独测试 Hook 逻辑
➕ 扩展功能
可以进一步扩展 Hook,添加更多功能:
export function useGitCodeUser(username: string = 'CodexBai') {
// ... 基础实现
// 添加缓存机制
const [cache, setCache] = useState<Map<string, GitCodeUser>>(new Map());
// 添加重试机制
const retry = async (maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
return await fetchGitCodeUser(username);
} catch (e) {
if (i === maxRetries - 1) throw e;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
};
return { data, loading, error, refetch, retry };
}
🎨 UI 组件实现
🧩 组件结构
GitCodeProfileScreen
├── 加载状态 (ActivityIndicator)
├── 错误状态 (错误信息 + 重试按钮)
└── 数据展示
├── 头部 (头像 + 姓名 + 简介)
├── 统计信息 (仓库数、粉丝数、关注数)
└── 详细信息 (公司、位置、博客等)
🧵 样式设计要点
- 卡片式布局: 使用白色背景和阴影效果
- 响应式设计: 适配不同屏幕尺寸
- 加载状态: 清晰的加载指示器
- 错误处理: 友好的错误提示和重试按钮
🏆 最佳实践与优化建议
⚙️ Axios 实例配置
创建 Axios 实例,统一配置:
// utils/axiosInstance.ts
import axios from 'axios';
const axiosInstance = axios.create({
baseURL: 'https://api.gitcode.com/api/v5',
timeout: 10000,
headers: {
'Accept': 'application/json',
'User-Agent': 'DailyHotBundle/1.0',
},
});
// 请求拦截器
axiosInstance.interceptors.request.use(
(config) => {
// 可以在这里添加 token 等
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
// 统一错误处理
return Promise.reject(error);
}
);
export default axiosInstance;
⛔ 请求取消
处理组件卸载时的请求取消:
useEffect(() => {
const cancelTokenSource = axios.CancelToken.source();
fetchGitCodeUser(username, {
cancelToken: cancelTokenSource.token
}).then(setData).catch(setError);
return () => {
cancelTokenSource.cancel('Component unmounted');
};
}, [username]);
🔁 请求重试机制
实现自动重试:
async function fetchWithRetry(url: string, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await axios.get(url);
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
🗃️ 缓存策略
实现简单的内存缓存:
const cache = new Map<string, { data: GitCodeUser; timestamp: number }>();
const CACHE_DURATION = 5 * 60 * 1000; // 5分钟
export async function fetchGitCodeUser(username: string): Promise<GitCodeUser> {
const cached = cache.get(username);
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
return cached.data;
}
const data = await axios.get(`/users/${username}`);
cache.set(username, { data, timestamp: Date.now() });
return data;
}
🧬 TypeScript 类型安全
充分利用 TypeScript 类型:
// 定义响应类型
interface ApiResponse<T> {
data: T;
status: number;
message?: string;
}
// 使用泛型
async function fetchData<T>(url: string): Promise<T> {
const response = await axios.get<ApiResponse<T>>(url);
return response.data.data;
}
✅ 测试与验证
🧪 功能测试
- ✅ 正常加载用户信息
- ✅ 网络错误处理
- ✅ 超时处理
- ✅ 下拉刷新
- ✅ 错误重试
🧨 边界情况测试
- ✅ 用户不存在(404)
- ✅ 网络断开
- ✅ 服务器错误(500)
- ✅ 组件卸载时的内存泄漏
▶️ 运行验证
# Android
npm run android
# iOS
npm run ios
# 开源鸿蒙
npm run harmony

📥 5. 将新的 bundle.harmony.js 文件拷贝到开源鸿蒙壳工程资源目录 rawfile 中,替换已有的 bundle.harmony.js。

▶️ 6. 运行应用

❓ 常见问题与解决方案
❓ Q1: Axios 在 React Native 中无法使用?
A: React Native 0.72+ 已经内置了网络请求支持,Axios 可以直接使用。如果遇到问题,检查:
- 网络权限配置(Android:
AndroidManifest.xml) - iOS 网络安全配置(iOS 9+ 需要 HTTPS)
- 开源鸿蒙需要在
module.json5配置文件中配置网络权限
❓ Q2: 如何处理 CORS 错误?
A: React Native 不受浏览器 CORS 限制,但如果 API 服务器有 CORS 限制,需要:
- 联系后端开发者配置 CORS
- 或使用代理服务器
❓ Q3: 请求超时如何设置?
A: 在 Axios 配置中设置 timeout:
axios.get(url, {
timeout: 10000, // 10秒
});
❓ Q4: 如何取消正在进行的请求?
A: 使用 CancelToken 或 AbortController:
const source = axios.CancelToken.source();
axios.get(url, { cancelToken: source.token });
source.cancel('Operation canceled');
❓ Q5: 如何处理并发请求?
A: 使用 Promise.all 或 axios.all:
const [user1, user2] = await Promise.all([
fetchGitCodeUser('user1'),
fetchGitCodeUser('user2'),
]);
📌 总结
🧾 核心收获
- Axios 集成: 成功在 React Native 项目中集成 Axios,实现了更强大的网络请求功能
- 错误处理: 完善的错误处理机制,提升用户体验
- 代码组织: 清晰的分层架构(API → Hook → UI),易于维护和扩展
- TypeScript: 充分利用类型系统,提高代码质量和开发效率
🗂️ 项目结构
bundles/gitcodeProfile/
├── api.ts # API 接口层:类型定义 + 请求函数
├── hooks.ts # 数据层:自定义 Hook
├── screen.tsx # UI 层:用户界面
└── index.ts # 导出层:模块导出
🧰 技术栈
- React Native 0.72.5: 跨平台框架
- TypeScript 4.8.4: 类型安全
- Axios 1.6.7: HTTP 客户端
- 开源鸿蒙适配: 支持鸿蒙平台
🔗 参考资源
更多推荐



所有评论(0)