axios
是基于promise 运行在browser和node环境
基本使用
const btns = document.querySelectorAll("button");
btns[1].onclick = function() {
axios({
method:"POST",
url:"https:/xxx/list",
data:{
owId:"2"
}
}).then(res => {
console.log(res);
})
}
btns[0].onclick = function() {
axios({
method:"Get",
url:"https://xxx/list",
params:{
owId:"2"
}
}).then(res => {
console.log(res);
})
}
其他使用方法
axios.request({
method:"POST",
url:"https://xxx/list",
data:{
Id:"2"
}
}).then(res => {
console.log(res);
})
axios.post("https://xxx/list",{Id:"2"}).then(res => {
})
axios.get("https://xxx/list",{params:{Id:"2"}}).then(res => {
})
resquest配置对象
{
// 请求目标路径
url: '/user',
// 请求的方法
method: 'get', // default
//请求根路径
baseURL: 'https://some-domain.com/api/',
//发送请求前先将数据进行处理,处理后的数据返回给后台
transformRequest: [function (data, headers) {
// Do whatever you want to transform the data
return data;
}],
//响应后结果进行处理
transformResponse: [function (data) {
// Do whatever you want to transform the data
return data;
}],
// 请求头信息: 如果在头部加入 校验信息
headers: {'X-Requested-With': 'XMLHttpRequest'},
// 设置url参数,可以通过对象设置,可以替代:xxx/id=12345
params: {
ID: 12345
},
// 参数序列化,转换成字符串,
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// form表单提交参数
data: {
firstName: 'Fred'
},
// syntax alternative to send data into the body
// method post
// only the value is sent, not the key
data: 'Country=Brasil&City=Belo Horizonte',
//请求超时时间.
timeout: 1000, // default is `0` (no timeout)
//跨域请求,对cookie是否跨域,如果 true,跨域会携带cookie
withCredentials: false, // default
// 请求适配器
// Return a promise and supply a valid response (see lib/adapters/README.md).
adapter: function (config) {
/* ... */
},
// `auth` indicates that HTTP Basic auth should be used, and supplies credentials.
// This will set an `Authorization` header, overwriting any existing
// `Authorization` custom headers you have set using `headers`.
// Please note that only HTTP Basic auth is configurable through this parameter.
// For Bearer tokens and such, use `Authorization` custom headers instead.
//请求基础验证
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` indicates the type of data that the server will respond with
// options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
// browser only: 'blob'
//响应格式
responseType: 'json', // default
// `responseEncoding` indicates encoding to use for decoding responses (Node.js only)
// Note: Ignored for `responseType` of 'stream' or client-side requests
//响应编码
responseEncoding: 'utf8', // default
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
//做请求保护,携带标识
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
//做请求保护,携带标识
xsrfHeaderName: 'X-XSRF-TOKEN', // default
// `onUploadProgress` allows handling of progress events for uploads
// browser only
//上传回调
onUploadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// `onDownloadProgress` allows handling of progress events for downloads
// browser only
//下载回调
onDownloadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// `maxContentLength` defines the max size of the http response content in bytes allowed in node.js
//响应体的最大尺寸
maxContentLength: 2000,
// `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed
//响应体的最大尺寸
maxBodyLength: 2000,
// `validateStatus` defines whether to resolve or reject the promise for a given
// HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
// or `undefined`), the promise will be resolved; otherwise, the promise will be
// rejected.
//对成功状态
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
// `maxRedirects` defines the maximum number of redirects to follow in node.js.
// If set to 0, no redirects will be followed.
//
maxRedirects: 5, // default
// `socketPath` defines a UNIX Socket to be used in node.js.
// e.g. '/var/run/docker.sock' to send requests to the docker daemon.
// Only either `socketPath` or `proxy` can be specified.
// If both are specified, `socketPath` is used.
socketPath: null, // default
// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
// and https requests, respectively, in node.js. This allows options to be added like
// `keepAlive` that are not enabled by default.
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// `proxy` defines the hostname, port, and protocol of the proxy server.
// You can also define your proxy using the conventional `http_proxy` and
// `https_proxy` environment variables. If you are using environment variables
// for your proxy configuration, you can also define a `no_proxy` environment
// variable as a comma-separated list of domains that should not be proxied.
// Use `false` to disable proxies, ignoring environment variables.
// `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and
// supplies credentials.
// This will set an `Proxy-Authorization` header, overwriting any existing
// `Proxy-Authorization` custom headers you have set using `headers`.
// If the proxy server uses HTTPS, then you must set the protocol to `https`.
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` specifies a cancel token that can be used to cancel the request
// (see Cancellation section below for details)
cancelToken: new CancelToken(function (cancel) {
}),
decompress: true // default
}
axios 默认配置(简化代码)
const btns = document.querySelectorAll("button");
//默认配置
axios.defaults.method = "POST";
axios.defaults.baseURL = "https://xxx"
axios.defaults.withCredentials = true;
axios.defaults.timeout = 3000;
btns[1].onclick = function() {
axios({
url:"/list",
data:{
Id:"2"
}
}).then(res => {
console.log(res);
})
}
axios 实例对象(和axios一样,目的可以向不同服务器发送请求,配置不同的配置)
const instance = axios.create({
baseURL:"https://aaa.com",
timeout: 1000,
method:"POST"
})
const instance2 = axios.create({
baseURL:"https://bbb.com",
timeout: 3000,
method:"GET"
})
console.log(instance);
instance({
url:"/list",
data:{
Id:"2"
}
}).then(res => {
})
instance2({
url:"/list",
data:{
Id:"2"
}
}).then(res => {
})
axios 拦截器 interceptors(核心:请求拦截器后进先执行,响应拦截器先进先执行)
// 设置请求拦截器
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);
});
axios 取消请求
const btns = document.querySelectorAll("button");
let cancelCallBack = null;
btns[1].onclick = function() {
//实例对象没有 构造函数静态方法和属性
const instance = axios.create({
baseURL:"https://xxx.com",
timeout: 3000,
method:"POST"
})
instance({
url:"/list",
data:{
Id:"2"
},
cancelToken: new axios.CancelToken((c)=>{
cancelCallBack = c;
})
}).then(res => {
})
}
btns[2].onclick = function() {
cancelCallBack();
}
阅读axios源码学习到什么?
- axios对象创建:该对象既可以当对象使用,也可以当函数使用; 任何的发送请求都是有
request
方式执行
//Axios 构造函数
function Axios(config) {
this.defaults = config;
this.interceptors = {
request: {},
response: {}
}
}
Axios.prototype.request = function(config) {
console.log("发送ajax请求", config.method)
}
Axios.prototype.get = function(config) {
return this.request(config);
}
Axios.prototype.post = function(config) {
return this.request(config);
}
// 核心方法 生成axios对象: 当对象使用,也可以当方法使用
function createInstance(config) {
//实例化一个对象
let context = new Axios(config);// context.get() context.post(), 但是不能当作函数使用 context() X
//创建请求函数
let instance = Axios.prototype.request.bind(context);// 等价 context.request(), 但是不能当作对象使用 属性和方法
// 把Axios.prototype对象的方法添加到instance 函数对象中,但是没有构造函数中的属性 default interceptors
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context);
})
//给instance 添加 default interceptors
Object.keys(context).forEach(key => {
console.log(key)
instance[key] = context[key];
})
return instance;
}
let axios = createInstance({method:"post"})
axios({method:"post"}) //
axios.request({method:"post"})
axios发送请求过程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
//Axios 构造函数
function Axios(config) {
this.defaults = config;
this.interceptors = {
request: {},
response: {}
}
}
Axios.prototype.request = function(config) {
//发送请求
//1 创建promise对象,成功回调
let promise = Promise.resolve(config);
//2. 声明数组
let chains = [dispatchRequest, undefined];//undefined 占位
//调用 promise对象
let result = promise.then(chains[0], chains[1]);
// 返回 promise对象
return result;
}
// 1. 创建实例对象
function createInstance(config) {
//实例化一个对象
let context = new Axios(config);// context.get() context.post(), 但是不能当作函数使用 context() X
//创建请求函数
let instance = Axios.prototype.request.bind(context);// 等价 context.request(), 但是不能当作对象使用 属性和方法
// 把Axios.prototype对象的方法添加到instance 函数对象中,但是没有构造函数中的属性 default interceptors
Object.keys(Axios.prototype).forEach(key => {
instance[key] = Axios.prototype[key].bind(context);
})
//给instance 添加 default interceptors
Object.keys(context).forEach(key => {
console.log(key)
instance[key] = context[key];
})
return instance;
}
//2. dispatchRequest 函数; 处理分发 请求
function dispatchRequest(config) {
//调用适配器发送请求
return xhrAdapter(config).then(response => {
//对响应的结果处理,暂时不用处理
// ...
return response
}, error => {
throw error;
})
}
//3. adaper适配器; xhr发送请求
function xhrAdapter(config) {
return new Promise((resolve,reject) => {
//发送ajax请求 4步
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url);
xhr.setRequestHeader("Content-Type","application/json");
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
//对响应数据 一次格式返回
resolve({
config:config,
data: xhr.response,
headers:xhr.getAllResponseHeaders(),
request:xhr,
status: xhr.status,
statusText: xhr.statusText
});
}else {
reject(new Error("请求失败"))
}
}
}
//发送json
xhr.send(JSON.stringify(config.data));
})
}
// 测试
let axios = Axios.prototype.request.bind(null);
axios({
method:"POST",
url:"https:/xxx/list",
data:{
Id:"2"
}
}).then(res => {
console.log(res);
})
</script>
</html>
实现拦截器功能原理
通过这次手写拦截器功能,深入了解到,咋样给自己定义的对象添加自定义的遍历方法foreach,promise灵活运用,控制回调函数的执行顺序
-
axios原理图
模拟拦截器实现
//假设这是目标函数: 功能是发送请求的,因为异步所以用promise
function dispachRequest(config) {
return new Promise((resolve, reject) => {
setTimeout(() => {
//模拟成功状态和失败状态
// if (config.status == 200) {
// console.log("发送请求成功");
// resolve(config);
// } else {
// reject("放送请求失败")
// }
resolve(config);
}, 0);
})
}
//定义一个拦截器管理
//1. 存入回调函数
//2. 取出回调函数
function InterceptorManager() {
this.handlers = [];//存放不同拦截器的回调函数(成功和失败)
}
InterceptorManager.prototype.use = function (onResolved, onRejected) {
this.handlers.push({
onResolved,
onRejected
})
}
//给定义一个forEach方法:目的取出 handlers对应的回调函数
InterceptorManager.prototype.forEach = function (fn) {
myForEach(this.handlers, function(item) {
fn(item);
})
}
//自定义一个遍历方法
function myForEach(arr, fn) {
for(var i = 0; i < arr.length; i ++) {
// this指向, item, 索引, 原数据
fn.call(null, arr[i], i, arr);
}
}
//定义一个拦截器
let interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
}
//测试添加一些 拦截器回调函数
function addInterceptors() {
interceptors.request.use(function (config) {
console.log("请求拦截器成功 -- 1号")
return config;
}, function (error) {
console.log("请求拦截器失败-- 1号")
return Promise.reject(error);
});
interceptors.request.use(function (config) {
console.log("请求拦截器成功 -- 2号")
return config;
}, function (error) {
console.log("请求拦截器失败 -- 2号")
return Promise.reject(error);
});
//响应拦截器
interceptors.response.use(function (response) {
console.log("响应拦截器成功 -- 1号")
return response;
}, function (error) {
console.log("响应拦截器失败-- 1号")
return Promise.reject(error);
});
interceptors.response.use(function (response) {
console.log("响应拦截器成功 -- 2号")
return response;
}, function (error) {
console.log("响应拦截器失败 -- 2号")
return Promise.reject(error);
});
}
//添加测试拦截器
addInterceptors();
//主运行函数
function request(config) {
//1. 创建promise对象: 把配置参数传递给下一个promise
let promise = Promise.resolve(config);
//2. 定义一个数组
let chains = [dispachRequest, undefined];
//2.1 将请求拦截器插入到chains前面
interceptors.request.forEach(function(interceptor) {
//记住顺序,失败先插入,因为执行先是成功的
chains.unshift(interceptor.onResolved,interceptor.onRejected);
})
//2.2 将响应拦截器压入到chains后面
interceptors.response.forEach(function(interceptor) {
chains.push(interceptor.onResolved,interceptor.onRejected);
})
console.log(chains)
while (chains.length) {
promise = promise.then(chains.shift(),chains.shift())
}
//3. 调用promise对象
// let result = promise.then(chains[0], chains[1]);
//返回promise
return promise;
}
//模拟请求
request({ method: "post"}).then(
res => {
console.dir("请求完成的数据"+ res)
},
err => {
console.log(err)
}
);
关键效果图
- 将之前的 创建axios, 发送请求,拦截器,进行合并
总结不易,点波关注,万水千山总是情,点波关注行不行哟!!!