本文需对js
、es6
、webpack
、网络请求
等基础知识有基本了解php
相信axios
你们都用过或者什么其余的网络请求
相关的库,什么ajax
、fly.js
等等等等,光我用过的请求库就七八个,都大同小异html
本文并非要完彻底全一个字不差的实现axios
全部功能,没有意义,可是也会实现的七七八八,主要是感觉一下这个流程和架子、以及 这个项目怎么才能易于拓展、是否是易于测试的、可读性怎么样等等等等webpack
废话很少说,开搞~ios
老规矩先建一个空目录,而后打开命令行执行c++
yarn init -y
git
或es6
cnpm init -y
github
而后是引入webpack
,虽然本节不主讲webpack
,这里我稍微提一嘴,webpack
和webpack-cli
不光项目里要下载,全局也要下载,也就是 yarn global add webpack webpack-cli
web
执行命令,主要就须要这几个包,帮忙编译和调试的,babel
帮助尽可能兼容浏览器的,毕竟我们写代码确定充满了es6
ajax
yarn add webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env
接下来再在根目录建立webpack.config.js
来配置一下webpack
,而后再建一个src
目录,来存放我们这个库的代码,如今的目录就会是这个样子
先简单配置一下,后续有需求在加,这里就直接上代码了
~ webpack.config.js
const path = require('path');
module.exports = function() {
const dev = true;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
};
};
复制代码
这时候在src
里面,建一个index.js
,而后随便写点东西,像这样
而后终端执行webpack
命令
固然了,如今确定是不兼容的,要不我们一开始也不用下babel
了,我们能够试试,好比我如今index.js
加一句话
而后编译完能够看到结果也仍是let
,这确定不行
好的,那么接下来就是配置babel
,没什么可说的,这里直接放代码了,没什么可说的
const path = require('path');
module.exports = function() {
const dev = true;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/i,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
};
};
复制代码
而后,你们确定不但愿每次修改手动的去webpack
一下对吧?把webpack-dev-server
引进来
~ webpack.config.js
const path = require('path');
module.exports = function() {
const dev = true;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/i,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
devServer: {
port: 8000,
open: true,
},
};
};
复制代码
这时候,直接终端里运行webpack-dev-server
的话其实他会自动去找全局的模块,这样很差,因此。。。你懂的
直接package.json
里加上命令
~ package.json
{
"name": "axios",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "webpack-dev-server"
},
"dependencies": {
"@babel/core": "^7.7.7",
"@babel/preset-env": "^7.7.7",
"babel-loader": "^8.0.6",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
}
}
复制代码
而后yarn start
这时候会弹出一个html
固然了,默认是去找根下的index.html
,我们没有,因此在根下建一个,而后引入我们的axios.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>axios</title>
</head>
<body>
<script src="/axios.js"></script>
</body>
</html>
复制代码
刷新页面就会看到src/index.js
里的alert
生效了
而且 webpack-dev-server
也是能够的,改了代码页面会自动刷新
而后,我们就来配一下build
这里就很少废话了,直接上代码了
~ package.json
{
"name": "axios",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "webpack-dev-server --env.dev",
"build": "webpack --env.prod"
},
"dependencies": {
"@babel/core": "^7.7.7",
"@babel/preset-env": "^7.7.7",
"babel-loader": "^8.0.6",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
}
}
复制代码
~ webpack.config.json
const path = require('path');
module.exports = function(env={}) {
const dev = env.dev;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/i,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
devServer: {
port: 8000,
open: true,
},
};
};
复制代码
能够看到也是没问题的~
好的到这我本算是把webpack
相关的东西搭的差很少了,接下来就要开始忙正事了~
首先我们先来建一个common.js
,用来放公共的方法,先写一个断言
~ /src/common.js
export function assert(exp, msg = 'assert faild') {
if (!exp) {
throw new Error(msg);
}
}
复制代码
而后再建一个文件(我的习惯)/src/axios
主要的文件放在这
而后你们来看看axios
正经怎么用,是否是能够直接 axios({...})
或者axios.get
等等
在index.js
引入直接写一下结果,把指望用法写上,而后来补充内部怎么写
~ index.js
import axios from './axios';
console.log(axios);
axios({ url: '1.txt', method: 'post' });
axios.get('1.txt', { headers: { aaa: 123 } });
axios.post(
'1.txt',
{ data: 123 },
{
headers: {
bbb: 123,
},
},
);
复制代码
这时候就要考虑考虑了,我们能够直接写函数,这个没问题,不过那样太散了,我的不喜欢,不过也是能够的,因此这里我就写成类了,因为改为类了那么输出出去的确定得是一个实例
,既然是实例的话,那么确定也不能直接像函数同样直接()运行
没错,这时候就能够用到我们的proxy
了,js
的class
里的constructor
里是能够return
东西的,若是对这东西不太熟,建议先去看看js
的class
,这里就很少赘述,主要说明思想
简单来讲,我们能够return
一个proxy
对象,来代理我们返回的结果,从而达到我们既能够直接用class
的方式写,用的时候也能够直接跟函数同样()
调用
而后先来打印一下看看
~
这时候看页面的console
,这时候能够看到axios
就是一个proxy
对象,像这样
这时候还能看到一个报错,由于我们如今返回的是proxy
对象,不是实例类了,没有get
也是理所应当
可能有人会奇怪,为何这个proxy
监听的对象非要单独监听一个proxy
函数呢,直接监听this
不就好了么,注意,这实际上是不行的,了解proxy
的朋友应该知道,proxy
你用什么监听建立的这事儿很重要,若是你监听的是一个对象,那仍是不能直接调用,若是要是想直接像函数同样直接调用的话,那你监听的也必须是一个函数
像这样
而后我们来解决一下get
函数找不到的问题,来给proxy
加一个方法, 很简单,能够给proxy
加一个get
方法,有人来找他,直接返回从我这个类上找,不就完了么,不过稍微要注意一下这个this
,直接写this
的话指向的是这个proxy
function request() {}
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
let axios = new Axios();
export default axios;
复制代码
这时候再看,就没有报错了,而且get
和post
也能console
出来
这时候我们就能够接着写数据请求了。。。。。吗? 远远不够
axios
的参数有不少的多样性,我们想来大概总结一下
axios('1.txt',{})
axios({
url: '1.txt',
method
})
axios.get('1.txt')
axios.get('1.txt',{})
axios.post....
复制代码
等等吧,这一点,怎么才能把这么复杂多源的参数统一处理
第二就是axios
能够很是深度的定制参数,能够全局也能够单独定制,拦截器,transfrom
什么的,等等吧,默认值等等
首先先来一个default
,来定义一下这些默认值,这里稍微说一下这个X-Request-By
算是一个不成文的规范,这也是广泛请求库都愿意作的事,方便后台去判断你这个请求是来自ajax
仍是from
仍是浏览器的url
function request() {}
const _default = {
method: 'get',
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
let axios = new Axios();
export default axios;
复制代码
固然了,这里图简单,简单写着几个参数,本身喜欢能够再加不少东西,好比data
的默认值等等,先够用,后续不够用再加
这时候,我们来思考一下,这个default
要加给谁,直接axios.default = _default
么,固然不是,由于我们这个axios
到最后确定是须要axios.create
多个实例的,那么这时候就不行了,互相影响,prototype
就更不用说了
其实也很简单,每次建立的时候从_default
复制一份新的就能够了,直接JSON.parse(JSON.stringify(_default))
包一下就能够了,这也是性能最高的方式,而后稍微来改造一下代码
function request() {}
const _default = {
method: 'get',
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
Axios.create = Axios.prototype.create = function() {
let axios = new Axios();
axios.default = JSON.parse(JSON.stringify(_default));
return axios;
};
export default Axios.create();
复制代码
这里是给原型和实例都加了一个create
方法,由于我们可能直接用axios.create()
也可能直接用axios()
,纯加静态方法或者实例方法都知足不了我们的需求
这时候咱们来实验一下,先来console
一下axios.default
你会发现,undefined
,这是为何呢,在这里明明都已经添加了呀
由于这时候这个axios
并非一个对象,而是一个proxy
,我们还没给proxy
加set
方法对不对,加什么都加不上,这时候来改造一下代码
function request() {}
const _default = {
method: 'get',
baseUrl: "",
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
Axios.create = Axios.prototype.create = function() {
let axios = new Axios();
axios.default = JSON.parse(JSON.stringify(_default));
return axios;
};
export default Axios.create();
复制代码
这时候再看浏览器,就会发现这个default
就有了
以及我们来create
两个axios
,改一下参数试一下
两个实例参数也不影响,这也是很好的第n
步,这时候我们就已经完成axios
的四分之一了
我们如今实例间是不影响了,不过我们改改参数的时候毫不止直接axios.default.xxx
这么改,我们还应该有参数,像这样
这里我们能够直接改造一下axios.create
方法
~ axios.js
...
Axios.create = Axios.prototype.create = function(options={}) {
let axios = new Axios();
axios.default = {
...JSON.parse(JSON.stringify(_default)),
...options
};
return axios;
};
...
复制代码
直接展开替换一下就好了对不对,可是,真的么?
假设我们直接传了一个对象,里面有个headers
的话是否是就直接给我们的默认参数header
整个就得替换了呀,那这个就不太好,固然了,这个也看我们对本身这个库的需求,若是我们就想这么作,也到是没啥毛病,问题以下
那么这时候,我们就能够用一个小小的递归来搞定了
~ axios.js
...
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
function merge(dest, src) {
for (let name in src) {
if (typeof src[name] == 'object') {
if (!dest[name]) {
dest[name] = {};
}
merge(dest[name], src[name]);
} else {
dest[name] = src[name];
}
}
}
merge(res, options);
axios.default = res;
return axios;
};
...
复制代码
这时候再看,就没问题了
接下来,我们先不急着去写请求的参数,我们先把这个代码稍微规划规划,整理整理,毕竟全放在一个文件里,这个之后就无法维护了
目前拆分能够分几点
default
是否是能够用一个单独的文件来装merge
函数确定是公用的,能够放在我们的common.js
里request
也应该单独放在一个js
里来定义废话很少说,直接上代码
~ request.js
export default function request() {
}
复制代码
~ default.js
export default {
method: 'get',
baseUrl: '',
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
复制代码
~ common.js
export function assert(exp, msg = 'assert faild') {
if (!exp) {
throw new Error(msg);
}
}
export function merge(dest, src) {
for (let name in src) {
if (typeof src[name] == 'object') {
if (!dest[name]) {
dest[name] = {};
}
merge(dest[name], src[name]);
} else {
dest[name] = src[name];
}
}
}
复制代码
~ axios.js
import _default from './default';
import { merge } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
这时候就感受干净很多了,对不对
在写以前,我们先来看看axios
都有哪些支持的写法,而后再去考虑怎么写
大概来看 除了那个总的axios({...})
这三种方法是否是差很少呀,固然了,axios
里东西太多了,这里就简单实现这三个,说明问题为主,你们有兴趣能够本身加,无非是体力活
固然,能够看到axios
参数状况仍是蛮多的,这时候我们应该直接统一处理,无论传过来什么参数,我们都返回一个axios({})
这种,最终统一处理,这不是方便么
这里直接来先判断一下前两种状况
你会发现前两种状况除了这个method
都是同样的,那这个我们就能够抽出方法统一处理
~ axios.js
import _default from './default';
import { merge } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
_preprocessArgs(method, ...args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
} else {
return undefined;
}
return options;
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
而后这时候,我们以封装一个库的视角,确定须要对参数进行各类各样的校验,类型等等,不对的话给他一个正经的报错,帮助使用者来调试
我们以前在common.js
里写的assert
这时候就用上了
...
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
// ...
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
}
}
}
...
复制代码
这里的规则对应着上面写的axios
使用方式,大致来讲也差很少,把这些参数都校验好了,接下来,我们就能够写具体的个性化的处理了
顺便一说,这个地方固然也是能够重用的,不过不必,搞了一通其实也没减小多少代码,而且贼乱,也看我的,你们不喜欢能够本身修改
而后我们再来处理一下这个options
,而且console
一下
~ axios.js
import _default from './default';
import { merge, assert } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
} else {
return undefined;
}
console.log(options);
return options;
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
这时候我们来测试一下
~ index.js
import Axios from './axios';
Axios.get('1.json');
Axios.get('1.json', { headers: { a: 12 } });
Axios.post('1.php');
Axios.post('1.php', { a: 12, b: 5 });
Axios.post('1.php', [12, 5, 6]);
let form = new FormData();
Axios.post('1.txt', form);
Axios.post('1.txt', 'dw1ewdq');
Axios.post('1.json', form, { headers: { a: 213, b: 132 } });
Axios.delete('1.json');
Axios.delete('1.json', { parmas: { id: 1 } });
复制代码
这时候能够看到,妥妥的对不对?
而后呢。。。还没忘,我们还须要处理直接apply
的状况,也就是直接Axios()
这么调用的时候
不废话,直接上代码,跟get
其实差很少
~ axios.js
import _default from './default';
import { merge, assert } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
console.log(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
} else {
return undefined;
}
console.log(options);
return options;
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
而后来测试一下
没问题,固然为何method
是undefined
,由于这时候还没走到我们的default
呢,我们是在这决定默认请求值的,因此这里直接给个undefined
就行,而后我们应该把些options
全都和defaulft
处理完,丢给我们的request
函数去请求
而这个方法确定全部请求都须要,因此我们写一个公共方法
这个request
方法主要干的事四件事
import _default from './default';
import { merge, assert } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
_this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
console.log(options, 'request');
// 1. 跟this.default进行合并
// 2. 检测参数是否正确
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
这个合并很简单,我们以前写的merge
函数又派上用场了,修改一下代码
...
request(options) {
console.log(options);
// 1. 跟this.default进行合并
merge(options, this.default);
console.log(options);
// 2. 检测参数是否正确
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
...
复制代码
这时候能够看到,合并前和合并后数据就已经都有了,可是,这时候我们的header
就不该该是所有都有了,应该根据传过来的method
是什么来把对应的方式的header
和common
合并一下
request(options) {
// 1. 跟this.default进行合并
let _headers = this.default.headers;
delete this.default.headers;
merge(options, this.default);
this.default.headers = _headers;
//合并头
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
console.log(headers);
console.log(options);
// 2. 检测参数是否正确
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
复制代码
这里比较乱,因此我们先来捋一捋
我们目的是要让header
合并,不过合并的话就会有点小问题,以前在们在default
的里定义的common
、get
...也都会被复制过来,若是要是我们用if
判断 options.header.common == this.default.headers.common
而后delete
的话,这时候你会发现不行,由于我们也知道,你直接写两个对象判断就至关于直接new
了两个对象,那这时候判断确定不相等,那么我们是在何时复制的呢
就在我们封装的merge
里,以及还有不少地方都动过这个东西
而后,我们应该找到这个东西到底在何时就不同了,其实也就是我们这个request
函数里第一次merge
的时候
因此我们这里玩了一个小技巧,由于common
这些东西在底下都已经手动搞了,因此这里不须要他复制进来,因此先delete
了一下
让他在以前就进不去,delete
以后再给拿回去,两头不耽误,真好~
最后,我们把headers
赋值到我们的options.headers
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
merge(options, this.default);
this.default.headers = _headers;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
console.log(options);
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
复制代码
~ index.js
import Axios from './axios';
Axios('1.php');
Axios({
url: '2.php',
params: { a: 12, b: 3 },
headers: {
a: 12,
},
});
复制代码
测试一下结果
能够看到,没毛病~
而后我们再来看一下第二步,其实这个校验我们能够写的很是很是多值得校验的事儿,可是这里只说明意思,写几个就算,你们有兴趣能够多补一些
...
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
...
复制代码
第三步也是直接上代码了
~ axios.js
options.url=options.baseUrl+options.url;
delete options.baseUrl;
复制代码
~ common.js
export function assert(exp, msg = 'assert faild') {
if (!exp) {
throw new Error(msg);
}
}
export function merge(dest, src) {
for (let name in src) {
if (typeof src[name] == 'object') {
if (!dest[name]) {
dest[name] = {};
}
merge(dest[name], src[name]);
} else {
if (dest[name] === undefined) {
dest[name] = src[name];
}
}
}
}
复制代码
~ index.js
import Axios from './axios';
Axios('1.php', {
baseUrl: 'http://www.baidu.com/',
headers: {
a: 12,
},
});
Ï
复制代码
这时候再测试一下,能够看到,就没问题了
这里说明一下为何要改一下
merge
,加了一个判断,由于我们以前是直接替换掉,有没有都替换,这确定不行,不加上的话会把我们的baseUrl
干了
固然了,还有个小事儿我们须要处理一下,若是用你这个库的人脑子有病(固然,不考虑脑子有病的也能够),他写路径的时候是这么写的
你这个是否是又不行了呀,很简单,NodeJS
里有一个url
包,能够直接引过来用,webpack
会帮你把他打包起来,不过有一点须要注意,webpack
不是全部的东西都能打包的,好比fs
模块,甚至一些底层功能用c
和c++
写的系统包这确定就不行,不过一个url
问题不大
~ axios.js
import _default from './default';
import { merge, assert } from './common';
import request from './request';
const urlLib = require('url');
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
_this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
merge(options, this.default);
this.default.headers = _headers;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
console.log(options);
// 2. 检测参数是否正确
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
// 3. baseUrl 合并请求
options.url = urlLib.resolve(options.baseUrl, options.url);
delete options.baseUrl;
// 4. 正式调用request(options)
request(options);
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
这时候再测试一下
就没问题了
其实我们这个merge
如今还有很大的问题,由于我们最开始的想要的功能和我们如今的功能有差入
我们如今是被迫写了一个if
,改为了查漏补缺,那么其实后面有优先级的东西顺序应该都反过来
我们最开始的需求是什么,是想让这个dest
优先级最低,是能够被别人覆盖的,可是如今写了这个if
以后,变成他优先级最高了,那这个就不对,可是还不能去掉,去掉了以后这个合并就又出问题了
this.default
变了,这时候又须要复制一份,我们来写一个公共的方法放到
common.js
里
~ common.js
...
export function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
复制代码
以及我们这个顺序稍微颠倒一下,而后数据克隆一下
这个时候来测试一下
会发现是否是header
里的这些东西又回来了呀,缘由也很简单,由于我们在上面整个的default
给clone
下来了,因此我们把delete
这一块往上提提
这时候就没问题了
这个时候我们就应该来写第四步了 直接把options
给到我们的request
函数里就能够,零零碎碎的问题全都给它处理好了
而后来修改一下request.js
~ request.js
export default function request(options) {
console.log(options);
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, true);
for (let name in options.headers) {
xhr.setRequestHeader(name, options.headers[name]);
}
xhr.send(options.data);
}
复制代码
暂时先写一个简单的请求,而后我们来测试一下看看能不能发出去
首先先建一个txt
,方便我们测试,我就放到data
目录里了,像这样
而后改一下index.js
~ index.js
import Axios from './axios';
Axios('/data/1.txt', {
headers: {
a: 12,
},
});
复制代码
这时候我们能够看到,header
是加上了的,而且返回的东西也对
固然这个东西还没完,也是一个防止用户捣乱的事
若是用户给你的header
是这样的东西,那这个就不太好,因此最好仍是给它来一个编码
~ request.js
export default function request(options) {
console.log(options);
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, true);
for (let name in options.headers) {
xhr.setRequestHeader(
encodeURIComponent(name),
encodeURIComponent(options.headers[name]),
);
}
xhr.send(options.data);
}
复制代码
这就没问题了万一后台有点问题,一遇见冒号就算结束这种问题就能避免了
而后我们用的时候确定更多的时候是须要一个async
和await
一下,因此我们须要用Promise
来包一下
~ axios.js
export default function request(options) {
console.log(options);
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, true);
for (let name in options.headers) {
xhr.setRequestHeader(
encodeURIComponent(name),
encodeURIComponent(options.headers[name]),
);
}
xhr.send(options.data);
return new Promise((resolve, reject) => {
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr);
} else {
reject(xhr);
}
}
};
});
}
复制代码
以及这个时候,我们还有不少不少问题
code
,这个怎么作到配置webpack
只能兼容es6
,async
和await
是兼容不了的,这个该怎么配我们先来解决webpack
的问题,这个其实很简单,我们须要再按一个包 yarn add @babel/polyfill
而后打开webpack.config.js
修改一下entry
~ webpack.config.js
...
entry: ['@babel/polyfill','./src/index.js'],
...
复制代码
注意这个顺序是不能颠倒的
这样就能够兼容了,而后我们再来修改一下index.js
import Axios from './axios';
(async () => {
let res = await Axios('/data/1.txt', {
headers: {
a: 12,
b: '321fho:fdsf vfds; : ',
},
});
console.log(res);
})();
复制代码
能够看到结果是undefined
,这是由于我们根本没有返回我们的处理结果
这时候修改一下axios.js
import _default from './default';
import { merge, assert, clone } from './common';
import request from './request';
const urlLib = require('url');
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
return _this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
let result = clone(this.default);
merge(result, this.default);
merge(result, options);
this.default.headers = _headers;
options = result;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
// 2. 检测参数是否正确
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
// 3. baseUrl 合并请求
options.url = urlLib.resolve(options.baseUrl, options.url);
delete options.baseUrl;
// 4. 正式调用request(options)
return request(options);
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
这时候我们再看结果,是否是就能够了,固然了,我们确定不能就直接把原始的xml
对象返回回去,我们还要对返回的数据进行各类处理
我们先来简单的改一下axios.js
下的request
返回又一个promise
,这时候能够看到结果,一点毛病没有
可是我们这个东西全放在axios.js
里就太乱了,因此我们也单独把它拆除去
建两个文件一个是/src/response.js
一个是/src/error.js
而后这里axios.js
引入一下,而且处理的时候分别交给他们
而后response.js
里直接返回值就能够了
不过这个headers
稍微有点特别,须要单独调一个方法xhr.getAllResponseHeaders()
,不过这返回的是原始xhr
的头,这确定不行,因此我们须要来切一下
~ response.js
export default function(xhr) {
let arr = xhr.getAllResponseHeaders().split('\r\n');
let headers = {};
arr.forEach(str => {
if (!str) return;
let [name, val] = str.split(': ');
headers[name] = val;
});
return {
ok: true,
status: xhr.status,
statusText: xhr.statusText,
data: xhr.response,
headers,
xhr,
};
}
复制代码
这样就好了
transformRequest
&& transformResponse
这时候固然还不算完,由于我们如今的data
尚未任何处理,因此确定都是字符串,以及用户可能自定义这个处理方式,熟悉axios
的朋友应该知道,axios
有transformRequest
和transformResponse
方法
这时候我们先来改一下以前axios.js
里的request
方法
如今须要在第三步和第四步之间来处理一下请求
先把参数打印一下,而后修改一下index.js
的测试demo
为了测试方便我把1.txt
改为1.json
了,方便我们一会处理json
数据好看到效果
能够看到,这个参数是能够拿到的,那么接下来就比较简单了,直接来
这时候看请求,这个headers
就加上了
这里稍微提一嘴,为何我要delete
掉,虽然不delete
没什么关系,可是我但愿我这个request
保持干净
至于这个自定义返回结果,是否是就更简单了呀
这时候能够看眼结果,我没传transformResponse
,结果是这样
这时候就能够了
固然了,我们如今已经能够很灵活的运用了,不止单传这个json
里能够配参数,全局配置统一处理同样是能够的,我们来试试
以及不一样的实例之间,都是能够的
拦截器在一个请求库里确定是必不可少的,其实我们这个库写到如今,想加一个这玩意,实际上是很容易的
~ index.js
import Axios from './axios';
Axios.interceptors.request.use(function(config) {
config.headers.interceptors = 'true';
return config;
});
(async () => {
let res = await Axios('/data/1.json', {
headers: {
a: 12,
b: '321fho:fdsf vfds; : ',
},
});
console.log(res);
})();
复制代码
而后新建一个interceptor.js
~interceptor.js
class Interceptor {
constructor() {
this._list = [];
}
use(fn) {
this._list.push(fn);
}
list() {
return this._list;
}
}
export default Interceptor;
复制代码
~ axios.js
import _default from './default';
import { merge, assert, clone } from './common';
import request from './request';
import createResponse from './response';
import createError from './error';
const urlLib = require('url');
import Interceptor from './interceptor';
class Axios {
constructor() {
this.interceptors = {
request: new Interceptor(),
response: new Interceptor(),
};
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
return _this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
let result = clone(this.default);
merge(result, this.default);
merge(result, options);
this.default.headers = _headers;
options = result;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
// 2. 检测参数是否正确
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
// 3. baseUrl 合并请求
options.url = urlLib.resolve(options.baseUrl, options.url);
delete options.baseUrl;
// 4. 变换一下请求
const { transformRequest, transformResponse } = options;
delete options.transformRequest;
delete options.transformResponse;
if (transformRequest) options = transformRequest(options);
let list = this.interceptors.request.list();
list.forEach(fn => {
options = fn(options);
});
// 5. 正式调用request(options)
return new Promise((resolve, reject) => {
return request(options).then(
xhr => {
let res = createResponse(xhr);
if (transformResponse) res = transformResponse(res);
let list = this.interceptors.response.list();
list.forEach(fn => {
res = fn(res);
});
resolve(res);
},
xhr => {
let err = createError(xhr);
reject(err);
},
);
});
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = clone(_default);
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
复制代码
能够看到,基本上是同样的套路,主要就是把参数传过来而后调用一下而已
不过这里面有两个小小的问题须要处理
config
不对或者没返回我们理应给他返回错误信息,再校验一下,这时候你们应该能想到了,应该吧axios
校验这些参数单独搞一个函数,没什么技术含量,这里就很少赘述,你们有兴趣能够试一下forEach
,这时候就会致使一个问题,若是用户给你的是一个带async
的函数那就不行了,我们也要加上async
和await
,不过async
和await
里面返回一个promise
又很怪,这个你们有兴趣能够本身试试,或者评论区留言这时候来试一下效果
能够看到我们这个拦截器也算是完成了
本篇最终代码已上传github
,连接以下 github.com/Mikey-9/axi…
仍是那句话,我们本篇文章主要不是要完整的实现axios
,而是实现一个这样的库的思想,固然其中也有不少问题,欢迎你们在评论区留言或者能够加个人qq
或者微信
一块儿交流
篇幅略长,感谢观看
Thank You
qq:
916829411
复制代码
微信:
Dyy916829411
复制代码