目的
- axios默认值、参数实现
- 实现一个简单get请求
- 实现XHLHttpRequest
- axios拦截器
准备
零配置的打包工具 Parcel ,使用方式也很简单,在你的客户端目录下通过 npm init -y 初始化,通过 npm install parcel-bundler –save-dev 安装 Parcel ,然后在你的 package.json 文件中添加如下脚本:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "parcel ./*.html",
"build": "parcel build ./*.html"
},
开始
新建axios文件夹,在此文件夹下新建
- axios.js //主要代码,包括axios.create等方法的实现
- default.js //默认的参数
- index.js //就是一个导出文件
- Interceptor.js //拦截器
- mergeConfig.js //合并配置默认值和用户的自定义配置(直接拷的源码)
- request.js //XMLHttpReauest发请求
- utils.js //工具类函数 (直接拷的源码)
主要文件就是这些,
贴几份我觉的比较重要的代码
这里是在Axios类的prototype上新增create方法并在里面new了一个Axios实例同时给实例添加默认配置参数
Axios.create = Axios.prototype.create = function (config) {
let configOptions = mergeConfig(defaults, config);
console.log(configOptions, "configOptions");
let axios = new Axios(configOptions);
axios.defaultConfig = configOptions;
return axios;
};
请求的实现 利用Promise包裹原始请求,使之可以链式调用
export default function request(options) {
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url);
for (let key in options.headers) {
xhr.setRequestHeader(
encodeURIComponent(key),
encodeURIComponent(options.headers[key])
);
}
xhr.send(options.data);
return new Promise((resolve, reject) => {
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr);
resolve({
data: JSON.parse(xhr.responseText),
status: xhr.status,
statusText: xhr.statusText,
});
} else {
reject(xhr);
}
}
};
});
}
request 和response拦截器
拦截器的使用方法
axios.interceptors.request.use((config) => {
config.headers.token = "x-token-654321";
return config;
});
//响应拦截器
axios.interceptors.response.use((res) => {
console.log("请求响应信息", res);
return res;
});
所以在Axios 的构造函数里
constructor() {
this.interceptors = {
request: new Interceptor(),
response: new Interceptor(),
};
}
Interceptor 类的实现如下
class Interceptor {
constructor() {
this.handlers = [];
}
use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected,
});
return this.handlers.length - 1;
}
}
要实现在发请求之前调用request拦截器,在请求结束后调用response拦截器
就要如下,利用Promise.resolve 和promise.then()进行链式调用
request(config) {
let configOptions = mergeConfig(this.defaultConfig, config);
let promise = Promise.resolve(configOptions);
//请求拦截器
let requestHandlers = this.interceptors.request.handlers;
requestHandlers.forEach((handeler) => {
promise = promise.then(handeler.fulfilled, handeler.rejected);
});
//数据请求
promise = promise.then(request);//这里的request是promise包裹的XMLHttpRequest
//响应拦截器
let responseHandlers = this.interceptors.response.handlers;
responseHandlers.forEach((handler) => {
promise = promise.then(handler.fulfilled, handler.rejected);
});
return promise;
}
感觉就是一个发布订阅模式,在调用interceptors.request.use(fn,fn)或者interceptors.reponse.use(fn,fn)时,将需要执行的函数订阅(储存在数组)在调用request时发布(执行所有的函数)
具体代码 https://github.com/dz333333/esay-axios