1. Axios 概述
Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。它具有以下特点:
- 支持浏览器和 Node.js 环境
- 支持 Promise API
- 可以拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换 JSON 数据
2. Axios 的基本使用
发送 GET 请求
axios.get('https://api.example.com/data').then(response => {console.log(response.data);}).catch(error => {console.error(error);});axios.get('https://api.example.com/data') .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });axios.get('https://api.example.com/data') .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });
发送 POST 请求
axios.post('https://api.example.com/submit', {key: 'value'}).then(response => {console.log(response.data);}).catch(error => {console.error(error);});axios.post('https://api.example.com/submit', { key: 'value' }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });axios.post('https://api.example.com/submit', { key: 'value' }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });
3. Axios 配置选项
你可以通过配置对象来调整请求的行为:
axios({method: 'post',url: 'https://api.example.com/submit',data: {key: 'value'},headers: {'Content-Type': 'application/json'}}).then(response => {console.log(response.data);}).catch(error => {console.error(error);});axios({ method: 'post', url: 'https://api.example.com/submit', data: { key: 'value' }, headers: { 'Content-Type': 'application/json' } }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });axios({ method: 'post', url: 'https://api.example.com/submit', data: { key: 'value' }, headers: { 'Content-Type': 'application/json' } }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });
4. 创建 Axios 实例
可以创建预配置的 Axios 实例:
const instance = axios.create({baseURL: 'https://api.example.com',timeout: 1000,headers: {'X-Custom-Header': 'foobar'}});const instance = axios.create({ baseURL: 'https://api.example.com', timeout: 1000, headers: {'X-Custom-Header': 'foobar'} });const instance = axios.create({ baseURL: 'https://api.example.com', timeout: 1000, headers: {'X-Custom-Header': 'foobar'} });
5. 请求和响应拦截器
请求拦截器
axios.interceptors.request.use(function(config) {// 在发送请求之前做一些事情return config;},function(error) {// 处理请求错误return Promise.reject(error);});axios.interceptors.request.use( function(config) { // 在发送请求之前做一些事情 return config; }, function(error) { // 处理请求错误 return Promise.reject(error); } );axios.interceptors.request.use( function(config) { // 在发送请求之前做一些事情 return config; }, function(error) { // 处理请求错误 return Promise.reject(error); } );
响应拦截器
axios.interceptors.response.use(function(response) {// 对响应数据做点什么return response;},function(error) {// 对响应错误做点什么return Promise.reject(error);});axios.interceptors.response.use( function(response) { // 对响应数据做点什么 return response; }, function(error) { // 对响应错误做点什么 return Promise.reject(error); } );axios.interceptors.response.use( function(response) { // 对响应数据做点什么 return response; }, function(error) { // 对响应错误做点什么 return Promise.reject(error); } );
6. 错误处理
当使用 Axios 发送请求时,如果请求失败,Promise 将会被 reject,并且可以在 .catch()
块中捕获这个错误。下面是一个具体的示例:
axios.get('https://api.example.com/data').then(response => {console.log('Data received:', response.data);}).catch(error => {console.error('An error occurred:', error);// 你可以检查错误的不同属性来确定错误的类型if (error.response) {// 请求已发出,服务器也响应了状态码,但状态码不在 2xx 范围内console.log('Server responded with a status of:', error.response.status);console.log('Response data:', error.response.data);} else if (error.request) {// 请求已发出,但没有收到响应console.log('No response received:', error.request);} else {// 设置请求时发生了错误console.log('Error setting up the request:', error.message);}console.log('Error config:', error.config);});axios.get('https://api.example.com/data') .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); // 你可以检查错误的不同属性来确定错误的类型 if (error.response) { // 请求已发出,服务器也响应了状态码,但状态码不在 2xx 范围内 console.log('Server responded with a status of:', error.response.status); console.log('Response data:', error.response.data); } else if (error.request) { // 请求已发出,但没有收到响应 console.log('No response received:', error.request); } else { // 设置请求时发生了错误 console.log('Error setting up the request:', error.message); } console.log('Error config:', error.config); });axios.get('https://api.example.com/data') .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); // 你可以检查错误的不同属性来确定错误的类型 if (error.response) { // 请求已发出,服务器也响应了状态码,但状态码不在 2xx 范围内 console.log('Server responded with a status of:', error.response.status); console.log('Response data:', error.response.data); } else if (error.request) { // 请求已发出,但没有收到响应 console.log('No response received:', error.request); } else { // 设置请求时发生了错误 console.log('Error setting up the request:', error.message); } console.log('Error config:', error.config); });
在这个示例中,我们向 'https://api.example.com/data'
发送了一个 GET 请求。如果请求成功,我们将接收到服务器返回的数据;但如果请求失败,.catch()
块将被触发,你可以在其中处理错误。
错误对象 error
包含了许多有用的信息,比如:
error.response
:包含服务器的响应,如果有的话。它是一个包含data
、status
和headers
属性的对象。error.request
:包含创建的 XMLHttpRequest 对象,如果请求已经发出并且没有收到响应的话。error.message
:描述错误的字符串。error.config
:包含发送请求时的配置信息。
通过检查这些属性,可以更准确地定位错误原因,并采取相应的措施。例如,如果服务器返回了一个 404 错误,可能需要检查请求的 URL 是否正确;如果是 500 内部服务器错误,可能需要联系服务器管理员或开发者查看服务器日志。
7. 取消请求
可以创建一个 CancelToken 并在需要时取消请求:
const source = axios.CancelToken.source();axios.get('/user/12345', {cancelToken: source.token}).catch(thrown => {if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message);} else {// handle error}});// 取消请求source.cancel('Operation canceled by the user.');const source = axios.CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }).catch(thrown => { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error } }); // 取消请求 source.cancel('Operation canceled by the user.');const source = axios.CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }).catch(thrown => { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error } }); // 取消请求 source.cancel('Operation canceled by the user.');
8. 封装 Axios
封装 Axios 可以让代码更整洁,更容易管理。可以在一个模块中封装所有的请求方法:
import axios from 'axios';const apiClient = axios.create({baseURL: 'https://api.example.com',timeout: 1000,});// 封装 GET 请求const get = (url, params) => apiClient.get(url, { params }).then(res => res.data);// 封装 POST 请求const post = (url, data) => apiClient.post(url, data).then(res => res.data);// 封装 PUT 请求const put = (url, data) => apiClient.put(url, data).then(res => res.data);// 封装 DELETE 请求const del = url => apiClient.delete(url).then(res => res.data);// 封装 PATCH 请求const patch = (url, data) => apiClient.patch(url, data).then(res => res.data);// 导出这些方法export { get, post, put, del, patch };import axios from 'axios'; const apiClient = axios.create({ baseURL: 'https://api.example.com', timeout: 1000, }); // 封装 GET 请求 const get = (url, params) => apiClient.get(url, { params }).then(res => res.data); // 封装 POST 请求 const post = (url, data) => apiClient.post(url, data).then(res => res.data); // 封装 PUT 请求 const put = (url, data) => apiClient.put(url, data).then(res => res.data); // 封装 DELETE 请求 const del = url => apiClient.delete(url).then(res => res.data); // 封装 PATCH 请求 const patch = (url, data) => apiClient.patch(url, data).then(res => res.data); // 导出这些方法 export { get, post, put, del, patch };import axios from 'axios'; const apiClient = axios.create({ baseURL: 'https://api.example.com', timeout: 1000, }); // 封装 GET 请求 const get = (url, params) => apiClient.get(url, { params }).then(res => res.data); // 封装 POST 请求 const post = (url, data) => apiClient.post(url, data).then(res => res.data); // 封装 PUT 请求 const put = (url, data) => apiClient.put(url, data).then(res => res.data); // 封装 DELETE 请求 const del = url => apiClient.delete(url).then(res => res.data); // 封装 PATCH 请求 const patch = (url, data) => apiClient.patch(url, data).then(res => res.data); // 导出这些方法 export { get, post, put, del, patch };
9. 高级用法
高级请求通常涉及更复杂的场景,例如处理大量并发请求、错误重试、请求取消、请求和响应的转换、自定义请求和响应拦截器等。下面我将通过一些具体的例子来展示这些高级用法。
1. 并发请求
当需要同时发送多个请求并等待所有请求完成时,可以使用 Promise.all
或者 axios.all
方法:
axios.all([axios.get('https://api.example.com/users'),axios.get('https://api.example.com/posts')]).then(axios.spread((usersResponse, postsResponse) => {console.log(usersResponse.data);console.log(postsResponse.data);})).catch(errors => {console.error(errors);});axios.all([ axios.get('https://api.example.com/users'), axios.get('https://api.example.com/posts') ]) .then(axios.spread((usersResponse, postsResponse) => { console.log(usersResponse.data); console.log(postsResponse.data); })) .catch(errors => { console.error(errors); });axios.all([ axios.get('https://api.example.com/users'), axios.get('https://api.example.com/posts') ]) .then(axios.spread((usersResponse, postsResponse) => { console.log(usersResponse.data); console.log(postsResponse.data); })) .catch(errors => { console.error(errors); });
2. 错误重试
在某些情况下,可能需要在请求失败后自动重试。这可以通过使用中间件或自定义拦截器来实现:
const retryInterceptor = axios.interceptors.response.use(response => response,async error => {const originalRequest = error.config;if (error.response.status === 401 && !originalRequest._retry) {originalRequest._retry = true;try {const response = await axios.post('/auth/token');const token = response.data.token;originalRequest.headers['Authorization'] = `Bearer ${token}`;return axios(originalRequest);} catch (_error) {return Promise.reject(_error);}}return Promise.reject(error);});const retryInterceptor = axios.interceptors.response.use( response => response, async error => { const originalRequest = error.config; if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const response = await axios.post('/auth/token'); const token = response.data.token; originalRequest.headers['Authorization'] = `Bearer ${token}`; return axios(originalRequest); } catch (_error) { return Promise.reject(_error); } } return Promise.reject(error); } );const retryInterceptor = axios.interceptors.response.use( response => response, async error => { const originalRequest = error.config; if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const response = await axios.post('/auth/token'); const token = response.data.token; originalRequest.headers['Authorization'] = `Bearer ${token}`; return axios(originalRequest); } catch (_error) { return Promise.reject(_error); } } return Promise.reject(error); } );
3. 请求取消
在某些情况下,可能需要在请求发送后取消它。这可以通过 CancelToken
来实现:
const source = axios.CancelToken.source();axios.get('/user/12345', {cancelToken: source.token}).then(response => {console.log(response.data);}).catch(throwError => {if (axios.isCancel(throwError)) {console.log('Request canceled', throwError.message);} else {console.error('A request failed:', throwError);}});// 后面的某个时刻,取消请求source.cancel('Operation canceled by the user.');const source = axios.CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }) .then(response => { console.log(response.data); }) .catch(throwError => { if (axios.isCancel(throwError)) { console.log('Request canceled', throwError.message); } else { console.error('A request failed:', throwError); } }); // 后面的某个时刻,取消请求 source.cancel('Operation canceled by the user.');const source = axios.CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }) .then(response => { console.log(response.data); }) .catch(throwError => { if (axios.isCancel(throwError)) { console.log('Request canceled', throwError.message); } else { console.error('A request failed:', throwError); } }); // 后面的某个时刻,取消请求 source.cancel('Operation canceled by the user.');
4. 请求和响应转换
可能需要在发送请求或接收到响应之前转换数据,例如序列化或反序列化数据:
axios({url: '/foo',method: 'post',data: { bar: 'baz' },transformRequest: [function(data) {// 将请求数据转换成字符串return JSON.stringify({ ...data });}],transformResponse: [function(data) {// 将响应数据转换成 JSON 对象return JSON.parse(data);}]}).then(response => {console.log(response.data);});axios({ url: '/foo', method: 'post', data: { bar: 'baz' }, transformRequest: [function(data) { // 将请求数据转换成字符串 return JSON.stringify({ ...data }); }], transformResponse: [function(data) { // 将响应数据转换成 JSON 对象 return JSON.parse(data); }] }) .then(response => { console.log(response.data); });axios({ url: '/foo', method: 'post', data: { bar: 'baz' }, transformRequest: [function(data) { // 将请求数据转换成字符串 return JSON.stringify({ ...data }); }], transformResponse: [function(data) { // 将响应数据转换成 JSON 对象 return JSON.parse(data); }] }) .then(response => { console.log(response.data); });
5. 自定义请求和响应拦截器
拦截器允许在请求被发送或响应被处理之前修改它们:
axios.interceptors.request.use(request => {// 在请求发送之前做一些事情console.log('Sending request:', request);return request;}, error => {// 处理请求错误return Promise.reject(error);});axios.interceptors.response.use(response => {// 在响应被传递给 then 前做一些事情console.log('Received response:', response);return response;}, error => {// 处理响应错误return Promise.reject(error);});axios.interceptors.request.use(request => { // 在请求发送之前做一些事情 console.log('Sending request:', request); return request; }, error => { // 处理请求错误 return Promise.reject(error); }); axios.interceptors.response.use(response => { // 在响应被传递给 then 前做一些事情 console.log('Received response:', response); return response; }, error => { // 处理响应错误 return Promise.reject(error); });axios.interceptors.request.use(request => { // 在请求发送之前做一些事情 console.log('Sending request:', request); return request; }, error => { // 处理请求错误 return Promise.reject(error); }); axios.interceptors.response.use(response => { // 在响应被传递给 then 前做一些事情 console.log('Received response:', response); return response; }, error => { // 处理响应错误 return Promise.reject(error); });
通过这些高级功能,可以根据不同的需求定制 Axios 的行为,以满足复杂的应用场景。在实际开发中,结合业务需求选择合适的策略是非常重要的。
10. 性能优化
使用缓存、优化请求头和压缩技术是提高网络请求效率和性能的重要手段。下面将针对这三点给出具体的示例。
1. 使用缓存机制
示例: 使用 axios-cache-adapter
库来缓存响应,减少不必要的网络请求。
首先,需要安装 axios-cache-adapter
:
npm install axios-cache-adapternpm install axios-cache-adapternpm install axios-cache-adapter
然后,在代码中使用它:
import axios from 'axios';import CacheAdapter from 'axios-cache-adapter';const cache = new CacheAdapter({maxAge: 60 * 1000, // 缓存有效期为1分钟});const cachedAxios = axios.create({adapter: cache.adapter,});// 发送请求,如果缓存中有数据则不会再次请求cachedAxios.get('https://api.example.com/data').then(response => {console.log('Data received:', response.data);}).catch(error => {console.error('An error occurred:', error);});import axios from 'axios'; import CacheAdapter from 'axios-cache-adapter'; const cache = new CacheAdapter({ maxAge: 60 * 1000, // 缓存有效期为1分钟 }); const cachedAxios = axios.create({ adapter: cache.adapter, }); // 发送请求,如果缓存中有数据则不会再次请求 cachedAxios.get('https://api.example.com/data') .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); });import axios from 'axios'; import CacheAdapter from 'axios-cache-adapter'; const cache = new CacheAdapter({ maxAge: 60 * 1000, // 缓存有效期为1分钟 }); const cachedAxios = axios.create({ adapter: cache.adapter, }); // 发送请求,如果缓存中有数据则不会再次请求 cachedAxios.get('https://api.example.com/data') .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); });
2. 优化请求头
示例: 仅在需要时发送特定的请求头,例如 If-None-Match
或 If-Modified-Since
,以利用 HTTP 的条件请求。
import axios from 'axios';let lastModified;axios.get('https://api.example.com/data', {headers: {'If-Modified-Since': lastModified,},}).then(response => {console.log('Data received:', response.data);lastModified = response.headers['last-modified'];}).catch(error => {if (error.response && error.response.status === 304) {console.log('Data has not been modified since the last request');} else {console.error('An error occurred:', error);}});import axios from 'axios'; let lastModified; axios.get('https://api.example.com/data', { headers: { 'If-Modified-Since': lastModified, }, }) .then(response => { console.log('Data received:', response.data); lastModified = response.headers['last-modified']; }) .catch(error => { if (error.response && error.response.status === 304) { console.log('Data has not been modified since the last request'); } else { console.error('An error occurred:', error); } });import axios from 'axios'; let lastModified; axios.get('https://api.example.com/data', { headers: { 'If-Modified-Since': lastModified, }, }) .then(response => { console.log('Data received:', response.data); lastModified = response.headers['last-modified']; }) .catch(error => { if (error.response && error.response.status === 304) { console.log('Data has not been modified since the last request'); } else { console.error('An error occurred:', error); } });
在这个例子中,如果服务器的数据没有改变,它会返回一个 304 Not Modified 的状态码,客户端就可以使用缓存中的数据,而无需下载新的数据。
3. 使用压缩技术
示例: 通过设置 Accept-Encoding
请求头来请求压缩的数据。
import axios from 'axios';axios.get('https://api.example.com/data', {headers: {'Accept-Encoding': 'gzip, deflate, br', // 支持 gzip, deflate 和 Brotli 压缩},}).then(response => {console.log('Data received:', response.data);}).catch(error => {console.error('An error occurred:', error);});import axios from 'axios'; axios.get('https://api.example.com/data', { headers: { 'Accept-Encoding': 'gzip, deflate, br', // 支持 gzip, deflate 和 Brotli 压缩 }, }) .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); });import axios from 'axios'; axios.get('https://api.example.com/data', { headers: { 'Accept-Encoding': 'gzip, deflate, br', // 支持 gzip, deflate 和 Brotli 压缩 }, }) .then(response => { console.log('Data received:', response.data); }) .catch(error => { console.error('An error occurred:', error); });
服务器如果支持压缩,会根据请求头中的 Accept-Encoding
字段来选择合适的压缩算法对响应体进行压缩,从而减少传输数据的大小,加快响应速度。
通过实施这些策略,可以显著提升应用的性能,减少用户的等待时间,同时降低服务器的带宽消耗。
结语
通过以上讲解,应该对 Axios 有了较为全面的理解。实践是检验学习成果的最佳方式,尝试在项目中应用 Axios,并不断探索其更多高级功能,会逐渐成为 Axios 的高手。如果遇到具体问题,查阅官方文档或寻求社区帮助都是很好的解决途径。
暂无评论内容