You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Axios原型上定义了request方法,该方法内做了传入的config参数合并,及生成promise链,确保请求时的执行顺序为axios请求->请求拦截器->dispatchRequest->响应拦截器->请求结束;为什么能够保证顺序,这是由promise的特性决定的,每个then方法内返回的都是一个新的promise对象,且只有当前promise的状态由pedding变更为fulfilled or rejected才会执行到下一个then or catch方法内;所以我们在拦截器内是可以做同步or异步操作的,如果我们直接在请求拦截器内reject,则接口不会发起请求;
使用adapter发起请求,成功回调内在通过throwIfCancellationRequested方法判断是否执行了取消cancel操作;Transform response data 返回json数据,并最终返回整个response;失败回掉内则根据isCancel是否取消了,来拼接失败返回的reason对象
目录:
一. 现有ajax请求库及方法的对比
二. axios常用的使用方式举例
三. axios源码分析
四. 通过了解axios源码之后,我们可以做哪些业务场景的优化
五. axios有哪些值得借鉴的地方
六. 总结
一、现有ajax请求库及方法的对比
二、axios常用的使用方式举例
第一种方式,axios(config)
第二种方式,axios(url[, config]),这时会默认为get请求
第三种方式,axios.get(url[, config])
第四种方式axios.post(url[,data[, config]])
第五种方式axios.request(config)
创建自定义实例,并添加拦截器
通过使用axios我们可能会有下面几个疑问?
然后让我们带着疑问,去源码内一探究竟;
三、axios源码分析
在分析源码之前在回顾一下一些关于XMLHttpRequest的基础知识
request header
在发送Ajax请求(实质是一个HTTP请求)时,我们可能需要设置一些请求头部信息,比如content-type、connection、cookie、accept-xxx等。xhr提供了setRequestHeader来允许我们修改请求 header,然而我们一般最关注content-type这个请求头属性的值;
如果不主动设置content-type,那么content-type会根据xhr.send(data)中data参数的数据类型来content-type的默认值
如果data是 Document 类型,同时也是HTML Document类型,则content-type默认值为text/html;charset=UTF-8;否则为application/xml;charset=UTF-8;
如果data是 DOMString 类型,content-type默认值为text/plain;charset=UTF-8;
如果data是 FormData 类型,content-type默认值为multipart/form-data; boundary=[xxx]
如果data是其他类型,则不会设置content-type的默认值
另外关于request header需要注意的是
方法的第一个参数 header 大小写不敏感,即可以写成content-type,也可以写成Content-Type,甚至写成content-Type;
setRequestHeader必须在open()方法之后,send()方法之前调用,否则会抛错;
setRequestHeader可以调用多次,最终的值不会采用覆盖override的方式,而是采用追加append的方式。下面是一个示例代码
xhr.responseType
responseType是xhr level 2新增的属性,用来指定xhr.response的数据类型
xhr.withCredentials与 CORS 什么关系
我们都知道,在发同域请求时,浏览器会将cookie自动加在request header中。而在发送跨域请求时,cookie并没有自动加在request header中。
造成这个问题的原因是:在CORS标准中做了规定,默认情况下,浏览器在发送跨域请求时,不能发送任何认证信息(credentials)如"cookies"和"HTTP authentication schemes"。除非xhr.withCredentials为true(xhr对象有一个属性叫withCredentials,默认值为false)。
所以根本原因是cookies也是一种认证信息,在跨域请求中,client端必须手动设置xhr.withCredentials=true,且server端也必须允许request能携带认证信息(即response header中包含Access-Control-Allow-Credentials:true),这样浏览器才会自动将cookie加在request header中。
axios源码目录,以最新的0.19.0-beta.1版本进行分析
axios的运行简图
从暴露出的axios的axios.js入口看起,在看axios.js之前需要先看下工具方法utils.js,因为axios.js内有用到这个extend、merge这几个工具方法
小结一下,axios.js内主要做了哪些事情
再来看下初始化Axios实例时传入的默认参数defaults,都定义在defaults.js内
小结一下default.js内定义了哪些默认参数
通过new Axios创建了Axios实例,那么看下Axios.js内做了些什么
看一张示意图
小结一下,Axios.js内主要做了哪些事情
接着看一下生成拦截器实例的InterceptorManager构造函数,在InterceptorManager.js内
小结一下,InterceptorManager.js内做了什么事情
然后我们在回过头来看dispatchRequest方法,在dispatchRequest.js内
小结一下dispatchRequest.js内做了哪些事情
dispatchRequest.js用到了adapter去发起请求,前面adapter属性会根据当前的运行环境去加载不同的适配器,我们已xhr.js为例
小结一下xhr.js内做的事情
最后让我们在看下axios内的取消请求是怎么实现的,源码在cancel目录下,主要看CancelToken.js
小结一下取消实现的逻辑:
到这里整个axios的内部实现基本已经阅读完毕,我们在回答下最开始的几个疑问
为什么axios可以直接调用,即axios({})
因为在axios是一个通过createInstance方法创建的函数,axios实际上就是Axios.prototype.request.bind(new Axios),所以axios可以直接调用
拦截器是怎么实现的
通过chian数组去维护一个按顺序排列的函数数组,然后通过while循环,将数组元素,两两一组的方式,传入promise.then方法内分别作为fullfiled及rejected函数,最后返回一个promise对象
怎样实现跨平台兼容的,即兼容浏览器端与node端
通过分别定义支持浏览器端的xhr.js与支持node端的http.js文件,然后通过但前运行的环境,加载对应的适配器
怎样去实现取消请求的
通过
new CancelToken((c) => {cancel = c})
实例,并传入一个函数参数,并在这个函数参数执行的时候,传入一个cancel函数,把取消的触发器赋值给一个外部变量,通过执行这个外部变量,来达到取消请求的目的;post请求默认是application/json,如果要发送表单请求该怎么做
两种方式,1.传入的data参数是URLSearchParams类型,即data参数经过qs.stringgify处理,第二种方式传入
headers: {Content-Type: 'application/x-www-form-urlencoded;charset=utf-8'}
,data参数经过qs.stringgify处理;注意config.headers >> config.headers[config.method] >> config.headers.common默认的请求转换器及响应转换器做了哪些事?
transformRequest:修正header内的Accept及Content-Type的属性名,然后根据data传入的数据,修改Content-Type属性值
transformResponse:JSON.parse(data)
注意这里的transformRequest及transformResponse是数组,我们可以通过axios.defaults.transformRequest = [function () {}]来覆盖,也可通过axios.defaults.transformRequest.push(() => {})来添加自定义转换器
为什么可以防止CSRF
什么是CSRF,CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一
axios就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略;这种方法貌似也有局限性
四、通过了解axios源码之后,我们可以做哪些业务场景的优化
五、axios有哪些值得借鉴的地方
模块的划分,简单明了,每个js文件又遵循功能单一原则;
拦截器的实现,借助了中间件的思路,又巧妙的运用了数组的unshif、push、shift方法、promise的特性,维持了一个可顺序执行的chain队列
用于发送请求功能的处理逻辑
axios没有将用于发送请求的dispatchRequest函数视为特殊函数。实际上,dispatchRequest函数被放置在chain队列的中间,以确保队列的处理一致性并提高代码的可读性。
在适配器的处理逻辑中,http和xhr模块(一个用于Node.js发送请求,另一个用于浏览器发送请求)不在dispatchRequest中直接用作其自己的模块,而是在默认情况下引入通过判断当前运行的环境来引入。因此,它不仅确保了两个模块之间的低耦合,而且为将来的用户留出了定制请求发送模块的空间。如我们需要添加微信小程序的适配器等;
在取消HTTP请求的逻辑中,axios被设计为使用Promise作为触发器,将resove函数作为参数传递给外部。它不仅可以确保内部逻辑的一致性,还避免最大程度地侵入其他模块。
六、总结
通过细读axios的源码,我们能够学到axios的设计,并了解其模块封装和交互思想;但是看懂了,并不代表自己学会了,所以还是需要自己去多练习,多总结。
参考链接:
https://fetch.spec.whatwg.org/#fetch-method
https://segmentfault.com/a/1190000004322487
camsong/blog#2
The text was updated successfully, but these errors were encountered: