您现在的位置是:亿华云 > IT科技
手写Axios核心原理
亿华云2025-10-09 01:21:00【IT科技】9人已围观
简介Axios是一个基于promise的HTTP库,它能够自动判断当前环境,自由切换在浏览器和 node.js环境中。如果是浏览器,就会基于XMLHttpRequests实现;如果是node环境,就会基于
Axios是手写一个基于promise的HTTP库,它能够自动判断当前环境,心原自由切换在浏览器和 node.js环境中。手写如果是心原浏览器,就会基于XMLHttpRequests实现;如果是手写node环境,就会基于node内置核心http模块实现。心原同时,手写它还用promise处理了响应结果,心原避免陷入回调地狱中去。手写
不仅如此,心原Axios还可以拦截请求和响应、手写转化请求数据和响应数据、心原中断请求、手写自动转换JSON数据、心原客户端支持防御XSRF等。手写如此众多好用的功能,快来一起看看它是如何实现的吧!
1.基本使用
axios基本使用方式主要有:
axios(config) axios.method(url,data,config) // 发送 POST 请求 axios({ method: post, url: /user/12345, data: { username: Web前端严选, age: 2 } }); // GET请求ID参数 axios.get(/user?ID=12345) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });2.实现axios
从axios(config)的使用上可以看出导出的axios是一个方法,从axios.get()的使用上可以看出导出的axios原型上会有get,post,put,delete等方法。
由分析可知,axios实际上是Axios类中的一个方法。云南idc服务商我们可以先写一个request方法来实现主要的请求功能,这样就能使用axios(config)形式来调用了。
class Axios{ constructor(){ } request(config){ return new Promise((resolve) => { const { url=,data={ },method=get} = config; //解构传参 const xhr = new XMLHttpRequest; //创建请求对象 xhr.open(method,url,true); xhr.onreadystatechange = () => { if(xhr.readyState == 4 && xhr.status == 200){ resolve(xhr.responseText); //异步请求返回后将Promise转为成功态并将结果导出 } } xhr.send(JSON.stringfy(data)); }) } } function CreateAxiosFn(){ let axios = new Axios; let req = axios.request.bind(axios); return req; } let axios = CreateAxiosFn();然后搭建一个简易服务端代码,以测试请求的效果:
const express = require(express) let app = express(); app.all(*, function (req, res, next) { res.header(Access-Control-Allow-Origin, *); res.header(Access-Control-Allow-Headers, Content-Type); res.header(Access-Control-Allow-Methods, *); res.header(Content-Type, application/json;charset=utf-8); next(); }); app.get(/getInfo, function(request, response){ let data = { username:前端严选, age:2 }; response.json(data); }); app.listen(3000, function(){ console.log("服务器启动"); });启动服务后,在页面中测试请求是否成功:
<button onclick="getMsg()">点击</button> <script src="./axios.js"></script> <script> function getMsg(){ axios({ method: get, url: http://localhost:3000/getInfo }).then(res => { console.log(res); }) } </script>点击按钮后,可以看到请求成功并获取到数据。
3.原型上的方法
接下来实现以axios.method()形式的方法。
通过axios.get(),axios.post(),axios.put()等方法可以看出它们都是Axios.prototype上的方法,这些方法调用内部的request方法即可:
const methodsArr = [get,post,put,delete,head,options,patch,head]; methodsArr.forEach(method => { Axios.prototype[method] = function(){ return this.request({ method: method, ...arguments[0] }) } })arguments的第一个参数包含url,data等信息,直接解构它的第一个元素即可
还需要实现一个工具方法,用来将b方法属性混入到a中去:
const utils = { extend(a,b,context){ for(let key in b){ if(b.hasOwnProperty(key)){ if(typeof b[key] == function){ a[key] = b[key].bind(context); }else{ a[key] = b[key] } } } } }最终导出axios的request方法,使之拥有get,post等方法
function CreateAxiosFn(){ let axios = new Axios; let req = axios.request.bind(axios); //新增如下代码 utils.extend(req, Axios.prototype, axios) return req; }再来测试一下post的请求:
axios.post({ url: http://localhost:3000/postTest, data: { a: 1, b: 2 } }).then(res => { console.log(res); })可以看到正确返回结果了。
4.拦截器
先来看看拦截器的使用:
// 请求拦截 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); });拦截器,顾名思义就是在请求之前和响应之前,对真正要执行的操作数据拦截住进行一些处理。
那么如何实现呢,云服务器提供商首先拦截器也是一个类,用于管理响应和请求。
class InterceptorsManage{ constructor(){ this.handlers = []; } use(onFulField,onRejected){ //将成功的回调和失败的回调都存放到队列中 this.handlers.push({ onFulField, onRejected }) } }axios.interceptors.response.use和axios.interceptors.request.use来定义请求和响应的拦截方法。
这说明axios上有响应拦截器和请求拦截器,那么如何在axios上实现呢:
class Axios{ constructor(){ this.interceptors = { request: new InterceptorsManage, response: new InterceptorsManage } } //.... }在Axios的构造函数中新增interceptors属性,然后定义request和response属性用于处理请求和响应。
执行use方法时,会把传入的回调函数放到handlers数组中。
这时再回看使用方式,axios.interceptors.request.use方法是绑在axios实例上的,因此同样需要把Axios上的属性和方法转移到request上,将interceptors对象挂载到request方法上。
function CreateAxiosFn() { let axios = new Axios(); let req = axios.request.bind(axios); utils.extend(req, Axios.prototype, axios) //新增如下代码 utils.extend(req, axios) return req; }但是现在request不仅要执行请求的发送,还要执行拦截器中handler的回调函数,因此还需要把request方法进行一下改造:
request(config){ //拦截器和请求的队列 let chain = [this.sendAjax.bind(this),undefined]; //请求的拦截 this.interceptors.request.handlers.forEach(interceptor => { chain.unshift(interceptor.onFulField,interceptor.onRejected); }) //响应的拦截 this.interceptors.response.handlers.forEach(interceptor => { chain.push(interceptor.onFulField,interceptor.onRejected) }) let promise = Promise.resolve(config); while(chain.length > 0){ //从头部开始依次执行请求的拦截、真正的请求、企商汇响应的拦截 promise = promise.then(chain.shift(),chain.shift()); } return promise; } sendAjax(config){ return new Promise((resolve) => { const { url=,method=get,data={ }} = config; const xhr = new XMLHttpRequest(); xhr.open(method,url,true); xhr.onreadystatechange = () => { if(xhr.readyState == 4 && xhr.status == 200){ resolve(xhr.responseText) } } xhr.send(JSON.stringify(data)); }) }最后执行chain的时候是这个样子的:
chain = [ //请求之前成功的回调和失败的回调 function (config) { return config; }, function (error) { return Promise.reject(error); } //真正的请求执行 this.sendAjax.bind(this), undefined, //请求之后响应的成功回调和失败回调 function (response) { return response; }, function (error) { return Promise.reject(error); } ]请求之前,promise执行为:
promise.then( function (config) { return config; }, function (error) { return Promise.reject(error); } )请求时,执行为:
promise.then( this.sendAjax.bind(this), undefined, )响应后,执行为:
promise.then( function (response) { return response; }, function (error) { return Promise.reject(error); } )这时我们测试一下拦截器的使用:
function getMsg(){ axios.interceptors.request.use((config) => { console.log(请求拦截:,config); return config; },err => { return Promise.reject(err) }) axios.interceptors.response.use(response => { response = { message: 响应数据替换, data: response } return response },err => { console.log(err,响应错误) return Promise.reject(err) }) axios.get({ url: http://localhost:3000/getTest, }).then(res => { console.log(res); }) }可以在控制台中看到拦截处理的打印输出,证明拦截成功!
5.总结
Axios天然支持Promise的性能让其方便对异步进行处理,同时又利用了Promise对请求进行了拦截,使得用户可以在请求过程中添加更多的功能,对请求的中断能自如操作。它的思想既清新朴实又不落入俗套,具有很好的借鉴意义。
看完这篇文章,你了解了Axios的核心原理了吗?
本文转载自微信公众号「Web前端严选」,可以通过以下二维码关注。转载本文请联系Web前端严选公众号。
很赞哦!(4479)
相关文章
- 如果你的潜在终端必须是这个米(域名),那么潜在终端并不多,也没有硬通货,那么你的域名应该在终端有兴趣购买时出售。否则,你可能得自己留着吃。
- 用Python轻松完成一个分布式事务TCC,保姆级教程
- 广告系统架构解密
- Python初学者请注意!别这样直接运行python命令
- 5、企业注册国内域名需要证件,其它情况一律不需要证件。
- 复杂的可过滤下拉选框?只需要一个Datalist 标签
- Node.js News - v16.x 发布为 LTS,异步上下文追踪处于稳定阶段
- 用容器与微服务安全来加持DevSecOps
- 比较短的域名方便用户记忆和传播,它带来的好处往往会超过其他类型的域名,如果你非要域名短而且还要包含关键词,那么往往会事与愿违,现在这种域名基本上是可遇而不可求的。
- 面试官:说说微信小程序的支付流程?