Axios你可能不知道使用方式(完善中)
2020/5/1 11:02:43
本文主要是介绍Axios你可能不知道使用方式(完善中),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
- 在前端日常开发中除了纯静态展示页面,必不可少的就是做一些接口请求,从
XMLHttpRequest
,到jQuery
的ajax
,再到后来的Fetch
和Axios
。
为什么选择Axios
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
为什么不用Fetch
- fetchtch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
- fetch默认不会带cookie,需要添加配置项(Axios也需要)
- fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行
- fetch没有办法原生监测请求的进度
基本配置
安装
# npm $ npm install axios # yarn $ yarn add axios # cdn <script src="https://unpkg.com/axios/dist/axios.min.js"></script> 复制代码
直接使用
1、使用.
执行某个请求方法,[method name]
包含了request
、head
、get
、put
、delete
、post
、patch
。
axios[method name](url[, data[, config]]) 复制代码
2、使用传入config
对象的方式调用
axios([config]) .then(response => response) .catch(error => error) // config 可选内容的配置选项。只有 url 是必需的。如果没有指定 method,请求将默认使用 get 方法。 { // `url` 是用于请求的服务器 URL url: '/user', // `method` 是创建请求时使用的方法 method: 'get', // 默认是 get // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。 // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL baseURL: 'https://some-domain.com/api/', // `headers` 是即将被发送的自定义请求头 headers: {'X-Requested-With': 'XMLHttpRequest'}, // `params` 是即将与请求一起发送的 URL 参数 // 必须是一个无格式对象(plain object)或 URLSearchParams 对象 params: { ID: 12345 }, ..., // `cancelToken` 指定用于取消请求的 cancel token // (查看后面的 Cancellation 这节了解更多) cancelToken: new CancelToken(function (cancel) { }) 复制代码
- 更多配置项请移步
Axios
官网,官网配置
3、并发处理
axios.all(iterable) axios.spread(callback) function getUserAccount() { return axios.get('/user/12345'); } function getUserPermissions() { return axios.get('/user/12345/permissions'); } axios.all([getUserAccount(), getUserPermissions()]) .then(axios.spread(function (acct, perms) { // 两个请求都执行完成 })); 复制代码
创建实例使用
- 通过
axios.create
创建请求实例,可接收一个config
对象;
import axios from axios; var instance = axios.create([config]); 复制代码
默认config
配置
1、配置请求超时时间
# 使用defaults axios.defaults.timeout = 30000 // 时间以毫秒为单位 # 使用实例传入config var instance = axios.create({ timeout: 30000 }); 复制代码
2、配置请求携带cookie
# 使用defaults axios.defaults.withCredentials = true // true为自动携带 # 使用实例传入config var instance = axios.create({ withCredentials: true }); 复制代码
3、配置baseURL
baseURL
将自动加在url
前面,除非url
是一个绝对 URL。
# 使用defaults axios.defaults.baseURL = 'https://github.com/detanx' # 使用实例传入config var instance = axios.create({ baseURL: 'https://github.com/detanx' }); 复制代码
4、配置headers
- 例如设置
token
# 使用defaults axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; # 使用实例传入config var instance = axios.create({ headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': AUTH_TOKEN }); 复制代码
5、取消请求cancelToken
- (1)使用
CancelToken.source
工厂方法创建cancelToken
。
const CancelToken = axios.CancelToken; const source = CancelToken.source(); axios.get(url, { cancelToken: source.token }).catch(thrown => thrown); // 取消请求(message 参数是可选的) source.cancel('cancel.'); 复制代码
- (2)通过传递一个
executor
函数到CancelToken
的构造函数来创建cancelToken
。
const CancelToken = axios.CancelToken; let cancel; axios.get(url, { cancelToken: new CancelToken(function executor(c) { // executor 函数接收一个 cancel 函数作为参数 cancel = c; }) }) // 取消请求(message 参数是可选的) cancel('cancel.'); 复制代码
6、更多
拦截器配置及错误处理
- 在请求或响应被
then
或catch
处理前拦截它们。
请求拦截
- 你可以直接添加到
import
进来的axios
上面,一般建议新建Axios
实例,将默认值及拦截器挂载到实例上。
1、拦截重复请求
const NotCancleUrl = ['/stockserver/user/login-user']; // 不取消重复请求的url列表 const pendingRequestArray = []; // 声明一个数组用于存储每个请求的取消函数和请求标识 const { CancelToken } = axios; const removePending = config => { for (const index in pendingRequestArray) { const key = `${config.url}&${config.method}`; if (pendingRequestArray[index].key === key && !NotCancleUrl.includes(config.url)) { // 当当前请求在数组中存在时执行函数体 pendingRequestArray[index].cancel(); // 执行取消操作 pendingRequestArray.splice(index, 1); // 把这条记录从数组中移除 } } }; // 添加请求拦截器 axios.interceptors.request.use( config => { // 例如添加取消重复请求 removePending(config); // 在一个发送请求前执行一下取消操作 config.cancelToken = new CancelToken(c => { // 这里的请求标识是用请求地址&请求方式拼接的字符串,你可以选择其他的一些方式 pendingRequestArray.push({ key: `${config.url}&${config.method}`, cancel: c }); }); return config; }, function (error) { // 处理请求错误 return Promise.reject(error); }); 复制代码
2、拦截请求地址,对地址中变量做替换
- 和其他开发人员约定,请求地址中变量通过
{{varname}}
包裹,变量对应应该替换的值传在请求的参数里面,通过替换变量,获得正确的请求地址。
/** 变量替换 /* requestUrl 含有变量的字符串 /* paramsObj 变量对象 /* return [] **/ const varsReplace = (requestUrl, paramsObj) => { const SYMBOL_REGEXP = /\{{(.+?)\}}/g; const VARS_ARRAY = requestUrl.match(SYMBOL_REGEXP); const newParamsObj = Object.assign({}, paramsObj); if (VARS_ARRAY){ for (const variable of VARS_ARRAY){ const varChartArray = variable.slice(2, -2); delete newParamsObj[varChartArray]; const value = paramsObj[varChartArray]; requestUrl = requestUrl.replace(variable, value); } } // 返回新的请求地址、剔除变量后的请求参数 return [requestUrl, newParamsObj]; }; // 添加发起拦截器 instance.interceptors.request.use( config => { let param = {}; param = (config.method === 'get') ? config.params : config.data; const [requestUrl, newParamsObj] = varsReplace(config.url, param); if (config.method === 'get') { config.params = newParamsObj; } else { config.data = newParamsObj; } config.url = requestUrl; return config; }, error => Promise.reject(error) ); 复制代码
响应拦截
1、 上面在请求拦截中做了重复请求的拦截,如果请求成功,我们应该在请求成功后,将相应的请求从pendingRequestArray
缓存请求的数组中移除。
// 添加响应拦截器 axios.interceptors.response.use( // 处理响应数据 response => { removePending(response.config); // 请求成功后,从pendingRequestArray中移除 return response; }, // 处理响应错误 error => { return Promise.reject(error); } ); 复制代码
2、对相应的请求超时、401
、403
状态做同一处理(当然你也可以根据你项目中实际的应用做一些其他的处理)。
axios.interceptors.response.use( response => response, error => { // 服务请求超时 if (error === undefined || error.code === 'ECONNABORTED') { message.warning('服务请求超时'); return Promise.reject(error); } const { response: { status } } = error; const { response } = error; const info = response.data; // 401未登录 if (status === 401) { // 未登录去重定向登录页面 ... } // 403访问被拒 if (status === 403) { ... } return Promise.reject(error); } ) 复制代码
错误处理
1、在请求的catch
方法中处理
axios.get(url) .catch(function (error) { if (error.response) { const { data, status, headers } = error.response; // 请求已发出,但服务器响应的状态码不在 2xx 范围内 console.log(data, status, headers); } else { // Something happened in setting up the request that triggered an Error console.log('Error', error.message); } console.log(error.config); }); 复制代码
2、使用validateStatus
配置选项定义一个自定义HTTP
状态码的错误范围。
axios.get(url), { validateStatus: function (status) { return status < 500; // 状态码在大于或等于500时才会 reject } }) 复制代码
项目中应用
- 默认设置及拦截器在之前已讲过,下面就只说请求方法实例封装。
通用使用封装
// 请求方法 export const AXIOS_METHOD_TYPET = { GET: 'GET', POST: 'POST', PUT: 'PUT', DELETE: 'DELETE', PATCH: 'PATCH' }; /** 方法说明 * @method request * @param api 请求相对地址 * @param method 请求方法,默认get * @param params 请求参数 默认为空 * @param config 请求配置 默认为空 * @return function 返回axios实例 */ const request = (api, method = AXIOS_METHOD_TYPET.GET, params = {}, config = {}) => { method = method.toLocaleUpperCase(); // get请求放在params中,其他请求放在body const data = method === 'GET' ? 'params' : 'data'; // 这部分也可以放到defaults中去设置 let headers = { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' }; if (config.headers) { headers = { ...headers, ...config.headers }; } return axios({ url: api, method, [data]: params, headers }); }; export default request; 复制代码
使用方式
// index.js import request from 'request'; request('/user/login', post, { username: 'detanx', password: '123456' }).then(response => console.log(response)) .catch(error => console.log(error)) 复制代码
hooks
调用封装
// useRequest.js import { useState, useEffect } from 'react'; // instance 为myAxios中暴露的添加了默认方法及拦截器的axios实例 import { instance, AXIOS_METHOD_TYPET } from './myAxios'; /** 方法说明 * @method useRequest * @return [ responseData, // 请求成功的返回 errorData, // 请求失败返回 loading, // 请求是否完成 setRequestParams // 参数改变重新请求 ] */ const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = {}, config = {}) => { method = method.toLocaleUpperCase(); const data = method === 'GET' ? 'params' : 'data'; const [responseData, setResponseData] = useState({}); const [errorData, setErrorData] = useState({}); const [loading, setLoading] = useState(true); const [requestParams, setRequestParams] = useState(params); let headers = { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' }; if (config.headers) { headers = { ...headers, ...config.headers }; } useEffect(() => { instance({ url, method, [data]: requestParams, headers }) .then(({ data }) => { setLoading(false); setResponseData(data); }) .catch(err => { setLoading(false); setErrorData(err); }); }, [requestParams]); return [ responseData, errorData, loading, setRequestParams ]; }; export default useRequest; 复制代码
使用方式
// index.js import useRequest from 'useRequest'; expoert default () => { const [ responseData, errorData, loading, setRequestParams ] = useRequest('/api/user', 'get') const clickHandle = () => { setRequestParams({name: 'detanx'}) } return (<> <button onClick={clickHandle}>新参数请求</button> </>) } 复制代码
hooks
封装完善
- 上面的封装会存在一个问题,就是每次使用
useRequest
都会直接发起一个请求,有些页面进来其实不需要请求,例如纯登录页面,只需要在提交登录信息时才需要发起请求,所以对上面的封装进行优化。约定params
为false
不发起请求。
// 修改params的默认值为false及默认不发送请求 const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = false, config = {}) => { ... useEffect(() => { // 约定`params`为`false`不发起请求 + if (requestParams === false) return; instance() }, [requestParams]); ... }; 复制代码
hooks
封装完善二
- 当一次请求成功后,后面相同的继续触发相同的请求,如果两次返回的成功数据或者失败数据是相同的,上述的代码是不会更新的。所以在
useRequest
中添加以下代码。
const useRequest = (url, method = AXIOS_METHOD_TYPET.GET, params = false, config = {}) => { ... - const [responseData, setResponseData] = useState({}); - const [errorData, setErrorData] = useState({}); - const [loading, setLoading] = useState(true); // 发起请求时再将loading设为true + const [responseData, setResponseData] = useState(null); + const [errorData, setErrorData] = useState(null); + const [loading, setLoading] = useState(false); + const reloadRequest = param => { + setResponseData(null); // 将成功数据重置为null + setErrorData(null); // 将失败数据重置为null + setRequestParams(param); // 发起新的请求 + }; useEffect(() => { if (requestParams === false) return; // 发起请求,loading设为true + setLoading(true); instance({}) ... }); - return [ + return { responseData, errorData, loading, - setRequestParams + reloadRequest - ] + }; } 复制代码
- 返回数组改为对象,数组的好处是强制对应每一个数据,对象可以自己取自己需要的数据。
后记
- 在日常的开发中大部分的需求已经足够了,如果你项目有其他的需求,欢迎留言。
- 对你有用的话,留下你的赞👍哦,感谢支持!
这篇关于Axios你可能不知道使用方式(完善中)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-03-14system bios shadowed
- 2024-03-14gabios
- 2024-02-07iOS应用提交上架的最新流程
- 2024-02-06打包 iOS 的 IPA 文件
- 2023-12-07uniapp打包iOS应用并通过审核:代码混淆的终极解决方案 ?
- 2023-11-25uniapp IOS从打包到上架流程(详细简单) 原创
- 2023-11-10【iOS开发】iOS App的加固保护原理:使用ipaguard混淆加固
- 2023-09-30最强大的iOS应用源码保护工具:Ipa Guard,保护你的商业机密代码
- 2023-09-07iOS安全加固探讨:代码混淆、类名方法名混淆等方法
- 2023-09-05iOS代码加固与保护方法详解 - 提升iOS应用安全性的关键步骤