axios是什么
axios是一个基于promise的http库,可以在浏览器和node.js中使用。目前前端最流行的ajax请求库。
react/vue官方都推荐使用axios发送ajax请求。
axios特点:
- axios是一个局域promise的HTTP库,支持promise所有的API
- axios可以连接请求和响应
- axios可以转换请求和响应数据,并对响应回来的内容自动转换成json类型的数据
- 浏览器端/node端都可以使用,浏览器中创建XMLHttpRequests
- 支持请求取消
- 批量发送多个请求
- 安全性高,客户端支持防御XSRF,就是让你的每个请求都带一个从cookies中拿到的key,根据浏览器同源策略,假冒的网站拿不到cookie中的key,这样后台可以轻松辨认出这个请求是否是用户在假冒网站上的舞蹈输入,从而采取正常策略。
axios常用方法
- axios(config): 通用/最本质的发任意类型请求的方式
- axios(url[, config]): 可以只指定 url 发 get 请求
- axios.request(config): 等同于 axios(config)
- axios.get(url[, config]): 发 get 请求
- axios.delete(url[, config]): 发 delete 请求
- axios.post(url[, data, config]): 发 post 请求
- axios.put(url[, data, config]): 发 put 请求
- axios.defaults.xxx: 请求的默认全局配置
- axios.interceptors.request.use(): 添加请求拦截器
- axios.interceptors.response.use(): 添加响应拦截器
- axios.create([config]): 创建一个新的 axios(它没有下面的功能)
- axios.Cancel(): 用于创建取消请求的错误对象
- axios.CancelToken(): 用于创建取消请求的 token 对象
- axios.isCancel(): 是否是一个取消请求的错误
- axios.all(promises): 用于批量执行多个异步请求
- axios.spread(): 用来指定接收所有成功数据的回调函数的方法
axios相关配置属性
axios({
method: 'post',//方法名
url: baseURL + '/post',//访问路径
headers: {
'content-type': 'application/json',
'name': 'zhufeng'
},
cancelToken: source.token,
timeout: 1000,
data: user
//params: user//get请求用params查询参数对象,它会转成查询字符串放到?的后面
})
- url:用于请求的服务器URL
- method:创建请求时默认使用的方法,默认get
- url:访问路径
- headers:即将被发送的自定义请求头
- params:即将与请求一起发送的URL参数
- get请求用params,post请求用data
- transformRequest:允许在向服务器发送前,修改请求数据,只能用在'PUT','POST'和'PATCH'这几个请求方法
axios为什么即能在浏览器运行,又能在服务器(node)环境运行
axios在浏览器端使用XMLHttpRequest对象发送的ajax请求,在node环境使用http对象ajax请求。
var defaults.adapter = getDefaultAdapter();
function getDefaultAdapter () {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
// 浏览器环境
adapter = require('./adapter/xhr');
} else if (typeof process !== 'undefined') {
// node环境
adapter = require('./adapter/http');
}
return adapter;
}
上面几行代码,可以看出:XMLHttpRequest 是一个 API,它为客户端提供了在客户端和服务器之间传输数据的功能;process 对象是一个 global (全局变量),提供有关信息,控制当前 Node.js 进程。原来作者是通过判断XMLHttpRequest和process这两个全局变量来判断程序的运行环境的,从而在不同的环境提供不同的http请求模块,实现客户端和服务端程序的兼容。
axios原理
axios本身是一个函数,axios底层有一个createInstance函数,函数创建一个Axios对象,axois中所有的请求内部调用的都是Axios.prototype.request,将Axios.prototype.request的内部this绑定到新建的Axios对象上,从而形成一个axios实例。新建一个Axios对象时,会有两个拦截器,request拦截器和response拦截器。
function createInstance(): AxiosInstance {
let context: Axios<any> = new Axios();//this指针上下文
//让request方法里的this永远指向context 也就是new Axios()
let instance = Axios.prototype.request.bind(context);
//把Axios的类的实例和类的原型上的方法都拷贝到了instance上 也就是request方法上
instance = Object.assign(instance, Axios.prototype, context);
return instance as AxiosInstance;
}
let axios = createInstance();
拦截器原理
在Axios类中增加interceptor属性(拦截器),interceptor中有定义request和response分别为请求拦截器和响应拦截器,每一个拦截器中都有成功的回调和失败的回调
Axios.tsx:
export default class Axios<T> {
public defaults: AxiosRequestConfig = defaults;
public interceptors = {
request: new AxiosInterceptorManager<AxiosRequestConfig>(),
response: new AxiosInterceptorManager<AxiosResponse<T>>()
}
//T是用来限制响应对象response里data的类型
request(config: AxiosRequestConfig): Promise<AxiosRequestConfig | AxiosResponse<T>> {
config.headers = Object.assign(this.defaults.headers, config.headers);
if(config.transformRequest && config.data) {
config.data = config.transformRequest(config.data, config.headers);
}
// return this.dispatchRequest(config);
const chain: Array<Interceptor<AxiosRequestConfig> | Interceptor<AxiosResponse<T>>> = [
{onFulfilled: this.dispatchRequest}
]
this.interceptors.request.interceptors.forEach((interceptor: Interceptor<AxiosRequestConfig> | null)=>{
//向数组左侧添加一个元素
interceptor && chain.unshift(interceptor)
});
this.interceptors.response.interceptors.forEach((interceptor: Interceptor<AxiosResponse<T>> | null)=>{
interceptor && chain.push(interceptor)
});
// let promise: Promise<AxiosRequestConfig> = Promise.resolve(config);
let promise: any = Promise.resolve(config);
while(chain.length) {//如果长度大于0
const { onFulfilled, onRejected } = chain.shift()!;//unshift向数组的头部增加元素,shift从头部删除元素
promise = promise.then(onFulfilled, onRejected);
}
return promise;
}
AxiosInterceptorManager.tsx:
interface OnFulfilled<V> {
(value: V): V | Promise<V>
}
interface OnRejected {
(error: any): any
}
export interface Interceptor<V> {//某一个拦截器
onFulfilled?: OnFulfilled<V>;//成功的回调
onRejected?: OnRejected; //失败的回调
}
//T可能是AxiosRequestConfig也可能是AxiosResponse
export default class AxiosInterceptorManager<V> {
public interceptors: Array<Interceptor<V> | null> = []
//每当调用use的时候可以向拦截器管理器重添加一个拦截器
use(onFulfilled?: OnFulfilled<V>,onRejected?: OnRejected):number {
this.interceptors.push({
onFulfilled,
onRejected
})
return this.interceptors.length =1
}
eject(id: number) {
if(this.interceptors[id]){
this.interceptors[id] = null
}
}
}