axios实现
Posted lin-fighting
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了axios实现相关的知识,希望对你有一定的参考价值。
类型定义
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 $timeoutms exceed`);
;
// 请求拦截器
request.send(body);
);
重难点
- 将所有的请求拦截+真正发请求的promise+响应拦截放入一个数组。
- 遍历使用promise.then去执行,一开始的config一直传
- 传到发送请求的promise后,就变成了data,然后data作为res继续传给响应拦截器。
- 简单的axios就完成了。
以上是关于axios实现的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Node、Express、Axios 在 ReactJS 前端设置带有 JWT 令牌的 cookie