类型定义
import { AxopsInterceptroManager } from './AxiosINterceptoManager'
interface AxiosInstace<T = any> {
// request方法
(config: AxiosRequestConfig):Promise<AxiosResponse<T>> //T是resolve(v)的v值的定义,
interceptors: {
request: AxopsInterceptroManager<AxiosRequestConfig>,
response: AxopsInterceptroManager<AxiosResponse<T>>
}
}
interface AxiosRequestConfig {
url?: string;
method?: Methods;
params?: Record<string, any>;
headers?: Record<string, any>
data?: Record<string, any>
timeout?: number
}
type Methods = 'get'|'GET'|'post'|'POST'|'put'|'PUT'|'delete'|'DELETE'
// 定义axios返回的类型
interface AxiosResponse<T=any>{
data:T,
status: number
statusText: string
headers: Record<string, any>
request: XMLHttpRequest
config?:AxiosRequestConfig
}
export type { AxiosInstace, AxiosResponse, AxiosRequestConfig }
index.ts
import { Axios } from './axios'
import { AxiosInstace, AxiosResponse } from './types'
function createInstance(){
let context: Axios = new Axios()
// 让request里面的方法永远指向context
let instance: AxiosInstace = Axios.prototype.request.bind(context)
// 把Axios的类的实例和类的原型上拷贝到request方法上。。
instance = Object.assign(instance, Axios.prototype, context)
return instance
}
let axios = createInstance()
export default axios
axios({url: '',params: {}, method: 'GET'}).then((res: AxiosResponse)=>{
console.log(res.data);
}).catch(err=>{})
//拦截器的基类
interface OnFulfilled<T>{
(v:T):T|Promise<T>
}
interface OnReject{
(error: any):any
}
// 存放着每次use的值
export interface Interceptor<T> {
onFulfilled?: OnFulfilled<T>
onRejected?: OnReject
}
interface AxiosInterceptorManager<T>{
use(onFuilled?:OnFulfilled<T>, onRejected?: OnReject):number
eject(id: number): void
}
// 类 interceptors.request/response的实例
export class AxopsInterceptroManager<T> implements AxiosInterceptorManager<T> {
public interceptors: Array<Interceptor<T> | null> = []
// 每次use,就将两个方法存入数组
use(onFulfilled: OnFulfilled<T> = v=>v, onRejected: OnReject = r=>r): number {
this.interceptors.push({
onFulfilled,
onRejected
})
return this.interceptors.length -1 // 返回索引
}
eject(id: number): void {
if(this.interceptors[id]){
this.interceptors[id] = null
}
}
}
主要逻辑
import * as qs from "qs";
import { AxopsInterceptroManager, Interceptor } from "./AxiosINterceptoManager";
import { AxiosInstace, AxiosRequestConfig, AxiosResponse } from "./types";
// T是响应数据
export class Axios<T = any> {
// 拦截器
public interceptors = {
// 实例,里面有数组,存放着所有的请求篮球机器
request: new AxopsInterceptroManager<AxiosRequestConfig>(),
reponse: new AxopsInterceptroManager<AxiosResponse<T>>(),
};
// 限制response的data的类型
request(config: AxiosRequestConfig): Promise<AxiosRequestConfig | AxiosResponse<T>> {
const chain: Interceptor<AxiosRequestConfig | AxiosResponse<T>>[] = [
// 真正的请求
{
onFulfilled: this.dispatchRequest,
onRejected: (error) => error,
},
];
// 获取所有注册的请求拦截器
this.interceptors.request.interceptors.forEach(
(interceptor: Interceptor<AxiosRequestConfig> | null) => {
// 后注册的放入队头
interceptor && chain.unshift(interceptor);
}
);
// 获取所有注册的响应拦截器
this.interceptors.reponse.interceptors.forEach(
(interceptor: Interceptor<AxiosResponse<T>> | null) => {
// 后注册的放入对尾
interceptor && chain.push(interceptor);
}
);
let promise:Promise<AxiosRequestConfig | AxiosResponse<T>> = Promise.resolve(config)
// 执行拦截器和真正的请求
while(chain.length){
const {onFulfilled, onRejected} = chain.shift()! //取出第一个执行
// 将config传入并且改造,然后他会继续返回,下一次Promise.then的时候就是新的config了
// 到了真正的请求,返回的值就是resolve(data)了,就是返回的data,然后继续将返回的data往下传递。
promise = promise.then(onFulfilled, onRejected)
}
return promise
}
// 派发请求
dispatchRequest<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest();
let query: string = "";
let { method = "get", url = "", params, data, headers, timeout } = config;
// 处理headers
if (params && typeof params === "object") {
// {a:1, b:2} => a=1&b=2
query = qs.stringify(params);
}
request.open(`${method}${query ? "?" + query : ""}`, url, true);
request.responseType = "json";
// 处理响应体
request.onreadystatechange = function () {
if (
request.readyState &&
request.status >= 200 &&
request.status <= 300
) {
// 响应拦截器
const response: AxiosResponse<T> = {
data: request.response ? request.response : request.responseText,
status: request.status,
statusText: request.statusText,
config,
headers: request.getAllResponseHeaders, // 响应头
request,
};
resolve(response);
} else {
// 状态码错误
reject(`Error: Request failed with status code ${request.status}`);
}
};
// 处理headers
if (headers) {
for (let key in headers) {
request.setRequestHeader(key, headers[key]);
}
}
// 处理post的body
let body: string | null = null;
if (data) {
body = JSON.stringify(data);
}
//错误处理
// 网络错误
request.onerror = function () {
reject("net:: ERR_INTERNET_DISCONNECTED");
};
// 超时错误
if (timeout) {
request.timeout = timeout;
request.ontimeout = function () {
reject(`Error: timeout of ${timeout}ms exceed`);
};
}
// 请求拦截器
request.send(body);
});
}
}
重难点
- 将所有的请求拦截+真正发请求的promise+响应拦截放入一个数组。
- 遍历使用promise.then去执行,一开始的config一直传
- 传到发送请求的promise后,就变成了data,然后data作为res继续传给响应拦截器。
- 简单的axios就完成了。