Skip to content

网络请求:Axios 库 ​

React Native 进阶 ​

Axios 是一个流行的 HTTP 客户端库,它提供了更强大、更灵活的网络请求功能,相比原生的 Fetch API,Axios 提供了更多的特性,如拦截器、自动转换 JSON 数据、请求取消等。本文将详细介绍如何在 React Native 中使用 Axios 进行网络请求。

1. 安装 Axios ​

首先,需要安装 Axios 库。

bash
# 使用 npm
npm install axios

# 使用 yarn
yarn add axios

2. 基本用法 ​

发送 GET 请求 ​

使用 Axios 发送 GET 请求,获取服务器数据。

jsx
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, FlatList, ActivityIndicator } from 'react-native';
import axios from 'axios';

export default function AxiosGetExample() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    try {
      setLoading(true);
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
      setData(response.data);
      setError(null);
    } catch (err) {
      setError(err.message);
      setData([]);
    } finally {
      setLoading(false);
    }
  };

  const renderItem = ({ item }) => (
    <View style={styles.item}>
      <Text style={styles.title}>{item.title}</Text>
      <Text style={styles.body}>{item.body}</Text>
    </View>
  );

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#4CAF50" />
        <Text style={styles.loadingText}>加载中...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.errorText}>{error}</Text>
      </View>
    );
  }

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={item => item.id.toString()}
      style={styles.container}
      contentContainerStyle={styles.content}
    />
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  content: {
    padding: 16,
  },
  item: {
    backgroundColor: '#fff',
    padding: 16,
    marginBottom: 12,
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.1,
    shadowRadius: 3.84,
    elevation: 5,
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 8,
  },
  body: {
    fontSize: 14,
    color: '#666',
  },
  center: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#666',
  },
  errorText: {
    fontSize: 16,
    color: '#f44336',
  },
});

发送 POST 请求 ​

使用 Axios 发送 POST 请求,向服务器提交数据。

jsx
import React, { useState } from 'react';
import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert } from 'react-native';
import axios from 'axios';

export default function AxiosPostExample() {
  const [title, setTitle] = useState('');
  const [body, setBody] = useState('');
  const [loading, setLoading] = useState(false);
  const [responseData, setResponseData] = useState(null);

  const handleSubmit = async () => {
    if (!title || !body) {
      Alert.alert('提示', '请输入标题和内容');
      return;
    }

    try {
      setLoading(true);
      const response = await axios.post('https://jsonplaceholder.typicode.com/posts', {
        title,
        body,
        userId: 1,
      });

      setResponseData(response.data);
      Alert.alert('成功', '数据提交成功');
    } catch (err) {
      Alert.alert('错误', err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>发送 POST 请求</Text>
      
      <View style={styles.formGroup}>
        <Text style={styles.label}>标题</Text>
        <TextInput
          style={styles.input}
          value={title}
          onChangeText={setTitle}
          placeholder="请输入标题"
        />
      </View>

      <View style={styles.formGroup}>
        <Text style={styles.label}>内容</Text>
        <TextInput
          style={[styles.input, styles.textArea]}
          value={body}
          onChangeText={setBody}
          placeholder="请输入内容"
          multiline
          numberOfLines={4}
        />
      </View>

      <TouchableOpacity
        style={[styles.button, loading && styles.buttonDisabled]}
        onPress={handleSubmit}
        disabled={loading}
      >
        <Text style={styles.buttonText}>
          {loading ? '提交中...' : '提交'}
        </Text>
      </TouchableOpacity>

      {responseData && (
        <View style={styles.response}>
          <Text style={styles.responseTitle}>响应数据:</Text>
          <Text style={styles.responseText}>ID: {responseData.id}</Text>
          <Text style={styles.responseText}>标题: {responseData.title}</Text>
          <Text style={styles.responseText}>内容: {responseData.body}</Text>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
    textAlign: 'center',
  },
  formGroup: {
    marginBottom: 16,
  },
  label: {
    fontSize: 16,
    marginBottom: 8,
    fontWeight: '500',
  },
  input: {
    backgroundColor: '#fff',
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    fontSize: 16,
  },
  textArea: {
    height: 120,
    textAlignVertical: 'top',
  },
  button: {
    backgroundColor: '#4CAF50',
    padding: 16,
    borderRadius: 8,
    alignItems: 'center',
    marginTop: 16,
  },
  buttonDisabled: {
    backgroundColor: '#9e9e9e',
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '500',
  },
  response: {
    marginTop: 24,
    padding: 16,
    backgroundColor: '#e8f5e8',
    borderRadius: 8,
  },
  responseTitle: {
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 8,
  },
  responseText: {
    fontSize: 14,
    marginBottom: 4,
  },
});

3. 常用配置 ​

设置请求头 ​

在发送请求时设置自定义请求头。

jsx
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import axios from 'axios';

export default function AxiosHeadersExample() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchWithHeaders();
  }, []);

  const fetchWithHeaders = async () => {
    try {
      setLoading(true);
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1', {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer your-token-here',
        },
      });

      setData(response.data);
      setError(null);
    } catch (err) {
      setError(err.message);
      setData(null);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#4CAF50" />
        <Text style={styles.loadingText}>加载中...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.errorText}>{error}</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>带请求头的 GET 请求</Text>
      <View style={styles.dataContainer}>
        <Text style={styles.dataLabel}>ID:</Text>
        <Text style={styles.dataValue}>{data.id}</Text>
      </View>
      <View style={styles.dataContainer}>
        <Text style={styles.dataLabel}>标题:</Text>
        <Text style={styles.dataValue}>{data.title}</Text>
      </View>
      <View style={styles.dataContainer}>
        <Text style={styles.dataLabel}>内容:</Text>
        <Text style={styles.dataValue}>{data.body}</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
    textAlign: 'center',
  },
  center: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#666',
  },
  errorText: {
    fontSize: 16,
    color: '#f44336',
  },
  dataContainer: {
    backgroundColor: '#fff',
    padding: 16,
    marginBottom: 12,
    borderRadius: 8,
  },
  dataLabel: {
    fontSize: 14,
    color: '#666',
    marginBottom: 4,
  },
  dataValue: {
    fontSize: 16,
    fontWeight: '500',
  },
});

创建 Axios 实例 ​

创建一个配置好的 Axios 实例,方便在整个应用中使用。

jsx
// utils/axiosInstance.js
import axios from 'axios';

const API_BASE_URL = 'https://jsonplaceholder.typicode.com';

const axiosInstance = axios.create({
  baseURL: API_BASE_URL,
  timeout: 10000, // 10秒超时
  headers: {
    'Content-Type': 'application/json',
  },
});

// 请求拦截器
axiosInstance.interceptors.request.use(
  (config) => {
    // 在这里可以添加认证 token 等
    const token = 'your-token-here';
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
axiosInstance.interceptors.response.use(
  (response) => {
    // 在这里可以处理响应数据
    return response;
  },
  (error) => {
    // 在这里可以处理错误
    if (error.response) {
      // 服务器返回错误状态码
      console.error('Response error:', error.response.data);
    } else if (error.request) {
      // 请求已发送但没有收到响应
      console.error('Request error:', error.request);
    } else {
      // 请求配置出错
      console.error('Error:', error.message);
    }
    return Promise.reject(error);
  }
);

export default axiosInstance;

使用创建的 Axios 实例:

jsx
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import axiosInstance from '../utils/axiosInstance';

export default function AxiosInstanceExample() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    try {
      setLoading(true);
      const response = await axiosInstance.get('/posts');
      setData(response.data);
      setError(null);
    } catch (err) {
      setError(err.message);
      setData([]);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#4CAF50" />
        <Text style={styles.loadingText}>加载中...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.errorText}>{error}</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>使用 Axios 实例</Text>
      <Text style={styles.count}>获取到 {data.length} 条数据</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
    textAlign: 'center',
  },
  count: {
    fontSize: 18,
    textAlign: 'center',
  },
  center: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#666',
  },
  errorText: {
    fontSize: 16,
    color: '#f44336',
  },
});

4. 高级功能 ​

处理超时 ​

设置请求超时时间。

jsx
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import axios from 'axios';

export default function AxiosTimeoutExample() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchWithTimeout();
  }, []);

  const fetchWithTimeout = async () => {
    try {
      setLoading(true);
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts', {
        timeout: 5000, // 5秒超时
      });
      setData(response.data);
      setError(null);
    } catch (err) {
      setError(err.message);
      setData(null);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#4CAF50" />
        <Text style={styles.loadingText}>加载中...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.errorText}>{error}</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>超时处理示例</Text>
      <Text style={styles.count}>获取到 {data.length} 条数据</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
    textAlign: 'center',
  },
  count: {
    fontSize: 18,
    textAlign: 'center',
  },
  center: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#666',
  },
  errorText: {
    fontSize: 16,
    color: '#f44336',
  },
});

取消请求 ​

实现网络请求的取消功能。

jsx
import React, { useState, useRef } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator } from 'react-native';
import axios from 'axios';

export default function AxiosCancelExample() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const cancelTokenRef = useRef(null);

  const fetchData = async () => {
    try {
      setLoading(true);
      setError(null);
      
      // 创建取消令牌
      const source = axios.CancelToken.source();
      cancelTokenRef.current = source;

      const response = await axios.get('https://jsonplaceholder.typicode.com/posts', {
        cancelToken: source.token,
      });

      setData(response.data);
    } catch (err) {
      if (axios.isCancel(err)) {
        setError('请求已取消');
      } else {
        setError(err.message);
      }
      setData(null);
    } finally {
      setLoading(false);
    }
  };

  const cancelFetch = () => {
    if (cancelTokenRef.current) {
      cancelTokenRef.current.cancel('请求已取消');
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>取消请求示例</Text>
      
      <View style={styles.buttonContainer}>
        <TouchableOpacity
          style={[styles.button, styles.fetchButton, loading && styles.buttonDisabled]}
          onPress={fetchData}
          disabled={loading}
        >
          <Text style={styles.buttonText}>
            {loading ? '加载中...' : '开始请求'}
          </Text>
        </TouchableOpacity>
        
        <TouchableOpacity
          style={[styles.button, styles.cancelButton, !loading && styles.buttonDisabled]}
          onPress={cancelFetch}
          disabled={!loading}
        >
          <Text style={styles.buttonText}>取消请求</Text>
        </TouchableOpacity>
      </View>

      {error && (
        <View style={styles.messageContainer}>
          <Text style={styles.errorText}>{error}</Text>
        </View>
      )}

      {data && (
        <View style={styles.messageContainer}>
          <Text style={styles.successText}>成功获取到 {data.length} 条数据</Text>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 30,
    textAlign: 'center',
  },
  buttonContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 30,
  },
  button: {
    flex: 1,
    padding: 16,
    borderRadius: 8,
    alignItems: 'center',
    marginHorizontal: 10,
  },
  fetchButton: {
    backgroundColor: '#4CAF50',
  },
  cancelButton: {
    backgroundColor: '#f44336',
  },
  buttonDisabled: {
    backgroundColor: '#9e9e9e',
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '500',
  },
  messageContainer: {
    padding: 16,
    borderRadius: 8,
    marginTop: 20,
  },
  errorText: {
    fontSize: 16,
    color: '#f44336',
  },
  successText: {
    fontSize: 16,
    color: '#4CAF50',
  },
});

并发请求 ​

同时发送多个网络请求。

jsx
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
import axios from 'axios';

export default function AxiosConcurrentExample() {
  const [data, setData] = useState({
    posts: null,
    comments: null,
    albums: null,
  });
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchConcurrentData();
  }, []);

  const fetchConcurrentData = async () => {
    try {
      setLoading(true);

      // 同时发送多个请求
      const [postsResponse, commentsResponse, albumsResponse] = await Promise.all([
        axios.get('https://jsonplaceholder.typicode.com/posts'),
        axios.get('https://jsonplaceholder.typicode.com/comments'),
        axios.get('https://jsonplaceholder.typicode.com/albums'),
      ]);

      setData({
        posts: postsResponse.data,
        comments: commentsResponse.data,
        albums: albumsResponse.data,
      });
      setError(null);
    } catch (err) {
      setError(err.message);
      setData({
        posts: null,
        comments: null,
        albums: null,
      });
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#4CAF50" />
        <Text style={styles.loadingText}>加载中...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.errorText}>{error}</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>并发请求示例</Text>
      
      <View style={styles.dataContainer}>
        <Text style={styles.dataTitle}>帖子数量: {data.posts.length}</Text>
        <Text style={styles.dataTitle}>评论数量: {data.comments.length}</Text>
        <Text style={styles.dataTitle}>相册数量: {data.albums.length}</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
    textAlign: 'center',
  },
  dataContainer: {
    backgroundColor: '#fff',
    padding: 20,
    borderRadius: 8,
  },
  dataTitle: {
    fontSize: 18,
    marginBottom: 10,
  },
  center: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#666',
  },
  errorText: {
    fontSize: 16,
    color: '#f44336',
  },
});

5. 最佳实践 ​

1. 封装 Axios 实例 ​

创建一个配置好的 Axios 实例,统一处理请求和响应。

2. 使用拦截器 ​

利用 Axios 的拦截器功能,处理认证、错误等通用逻辑。

3. 错误处理 ​

实现全面的错误处理,包括网络错误、服务器错误和业务逻辑错误。

4. 取消请求 ​

在组件卸载或用户操作时,取消正在进行的请求,避免内存泄漏。

5. 超时设置 ​

为请求设置合理的超时时间,避免请求无限期等待。

6. 并发请求 ​

使用 Promise.all 处理并发请求,提高性能。

7. 缓存策略 ​

对于频繁访问的数据,实现合理的缓存策略,减少网络请求。

6. 常见问题与解决方案 ​

问题 1:CORS 错误 ​

问题:在开发过程中遇到 CORS 错误。

解决方案:

  • 在开发环境中使用代理服务器
  • 确保服务器设置了正确的 CORS 头
  • 考虑使用 JSONP 或其他跨域解决方案

问题 2:认证失败 ​

问题:需要认证的请求失败。

解决方案:

  • 确保正确设置认证头
  • 实现 token 刷新机制
  • 处理认证错误,引导用户重新登录

问题 3:请求取消不生效 ​

问题:调用取消方法后,请求仍然继续执行。

解决方案:

  • 确保正确使用 CancelToken
  • 在请求配置中正确设置 cancelToken
  • 检查取消逻辑是否在请求发送前执行

问题 4:拦截器不工作 ​

问题:请求或响应拦截器不执行。

解决方案:

  • 确保正确配置拦截器
  • 检查拦截器的返回值
  • 确保使用的是配置了拦截器的 Axios 实例

7. 总结 ​

Axios 是一个功能强大的 HTTP 客户端库,它提供了比原生 Fetch API 更多的特性,如拦截器、自动转换 JSON 数据、请求取消等。通过本文的学习,你应该掌握了以下内容:

  1. 安装和基本使用 Axios
  2. 发送 GET 和 POST 请求
  3. 设置请求头和创建 Axios 实例
  4. 使用拦截器处理请求和响应
  5. 实现超时处理和请求取消
  6. 发送并发请求
  7. 最佳实践和常见问题的解决方案

在实际开发中,合理使用 Axios 可以创建出更加可靠、高效的网络请求功能。通过结合其他技术,如状态管理和缓存策略,可以创建出更加专业、用户友好的应用。

© 2026 编程马·菜鸟教程 版权所有