From bfc012b4999d717629b997ab908fd411954b0323 Mon Sep 17 00:00:00 2001 From: zjx0905 <954270063@qq.com> Date: Tue, 25 Apr 2023 14:28:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E7=88=B6=E7=BA=A7=E4=B8=AD=E9=97=B4=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/axios.ts | 3 +- src/core/Axios.ts | 61 ++++++++++++--------- src/core/MiddlewareManager.ts | 85 +++++++++++++++-------------- src/core/createInstance.ts | 2 +- test/core/MiddlewareManager.test.ts | 79 --------------------------- 5 files changed, 82 insertions(+), 148 deletions(-) delete mode 100644 test/core/MiddlewareManager.test.ts diff --git a/src/axios.ts b/src/axios.ts index 920eec6..cbaae36 100644 --- a/src/axios.ts +++ b/src/axios.ts @@ -4,9 +4,8 @@ import { isCancel, } from './request/cancel'; import { isAxiosError } from './request/createError'; -import Axios, { AxiosConstructor, AxiosRequestConfig } from './core/Axios'; +import Axios, { AxiosConstructor } from './core/Axios'; import { AxiosInstance, createInstance } from './core/createInstance'; -import { mergeConfig } from './core/mergeConfig'; import { createAdapter } from './adpater/createAdapter'; import defaults from './defaults'; import { version } from './version'; diff --git a/src/core/Axios.ts b/src/core/Axios.ts index 415ccd8..915bf63 100644 --- a/src/core/Axios.ts +++ b/src/core/Axios.ts @@ -21,7 +21,10 @@ import { WITH_DATA_METHODS, WITH_PARAMS_METHODS, } from '../constants/methods'; -import MiddlewareManager from './MiddlewareManager'; +import MiddlewareManager, { + MiddlewareNext, + MiddlewareUse, +} from './MiddlewareManager'; /** * 请求方法 @@ -379,9 +382,7 @@ export default class Axios { /** * 中间件 */ - #middleware = new MiddlewareManager(async (ctx) => { - ctx.res = await dispatchRequest(ctx.req); - }); + #middleware = new MiddlewareManager(); /** * 发送 options 请求 @@ -431,17 +432,12 @@ export default class Axios { /** * 添加中间件 */ - use: MiddlewareManager['use']; + use: MiddlewareUse; constructor(defaults: AxiosRequestConfig = {}, parent?: Axios) { this.defaults = defaults; this.#parent = parent; - if (this.#parent) { - this.#middleware.flush = this.#parent.#middleware.wrap( - this.#middleware.flush, - ); - } - this.use = this.#middleware.use.bind(this.#middleware); + this.use = this.#middleware.use; } /** @@ -463,15 +459,7 @@ export default class Axios { #processRequest(config: AxiosRequestConfig) { const requestHandler = { - resolved: async (config: AxiosRequestConfig) => { - config.url = combineURL(config.baseURL, config.url); - const ctx: AxiosContext = { - req: config, - res: null, - }; - await this.#middleware.flush(ctx); - return ctx.res as AxiosResponse; - }, + resolved: this.#requestHandler, }; const errorHandler = { rejected: config.errorHandler, @@ -481,11 +469,11 @@ export default class Axios { | Partial> )[] = []; - this.#eacheRequestInterceptors((requestInterceptor) => { + this.#eachRequestInterceptors((requestInterceptor) => { chain.unshift(requestInterceptor); }); chain.push(requestHandler); - this.#eacheResponseInterceptors((responseInterceptor) => { + this.#eachResponseInterceptors((responseInterceptor) => { chain.push(responseInterceptor); }); chain.push(errorHandler); @@ -501,19 +489,40 @@ export default class Axios { ) as Promise; } - #eacheRequestInterceptors(executor: InterceptorExecutor) { + #eachRequestInterceptors(executor: InterceptorExecutor) { this.interceptors.request.forEach(executor); if (this.#parent) { - this.#parent.#eacheRequestInterceptors(executor); + this.#parent.#eachRequestInterceptors(executor); } } - #eacheResponseInterceptors(executor: InterceptorExecutor) { + #eachResponseInterceptors(executor: InterceptorExecutor) { this.interceptors.response.forEach(executor); if (this.#parent) { - this.#parent.#eacheResponseInterceptors(executor); + this.#parent.#eachResponseInterceptors(executor); } } + + #requestHandler = async (config: AxiosRequestConfig) => { + config.url = combineURL(config.baseURL, config.url); + const ctx: AxiosContext = { + req: config, + res: null, + }; + await this.#flush(ctx, async () => { + ctx.res = await dispatchRequest(ctx.req); + }); + return ctx.res as AxiosResponse; + }; + + #flush(ctx: AxiosContext, finish: MiddlewareNext): Promise { + if (this.#parent) { + return this.#parent.#flush(ctx, () => { + return this.#middleware.flush(ctx, finish); + }); + } + return this.#middleware.flush(ctx, finish); + } } for (const method of PLAIN_METHODS) { diff --git a/src/core/MiddlewareManager.ts b/src/core/MiddlewareManager.ts index 527d339..c019f53 100644 --- a/src/core/MiddlewareManager.ts +++ b/src/core/MiddlewareManager.ts @@ -6,32 +6,39 @@ export interface MiddlewareNext { (): Promise; } -export interface MiddlewareCallback { - (ctx: Conext, next: MiddlewareNext): Promise; +export interface MiddlewareCallback { + (ctx: Context, next: MiddlewareNext): Promise; } -export interface MiddlewareFlush { - (ctx: Conext): Promise; -} - -export default class MiddlewareManager { - #map = new Map[]>(); - - flush: MiddlewareFlush; - - constructor(flush: MiddlewareFlush) { - this.flush = this.wrap(flush); - } - - use(callback: MiddlewareCallback): MiddlewareManager; - use( +export interface MiddlewareUse { + /** + * 添加中间件 + * + * @param path 中间件路径 + * @param callback 中间件回调 + */ + ( path: string, - callback: MiddlewareCallback, - ): MiddlewareManager; - use( - path: string | MiddlewareCallback, - callback?: MiddlewareCallback, - ) { + callback: MiddlewareCallback, + ): MiddlewareManager; + /** + * 添加中间件 + * + * @param callback 中间件回调 + */ + (callback: MiddlewareCallback): MiddlewareManager; +} + +export default class MiddlewareManager { + #map = new Map[]>(); + + /** + * 添加中间件 + */ + use: MiddlewareUse = ( + path: string | MiddlewareCallback, + callback?: MiddlewareCallback, + ) => { if (isFunction(path)) { callback = path; path = '/'; @@ -45,27 +52,25 @@ export default class MiddlewareManager { this.#map.set(path, middlewares); return this; - } + }; - wrap(flush: MiddlewareFlush): MiddlewareFlush { - return (ctx) => { - const allMiddlewares: MiddlewareCallback[] = []; + flush(ctx: Context, finish: MiddlewareNext) { + const allMiddlewares: MiddlewareCallback[] = []; - for (const [path, middlewares] of this.#map.entries()) { - const url = combineURL(ctx.req.baseURL, path); - const checkRE = new RegExp(`^${url}([/?].*)?`); + for (const [path, middlewares] of this.#map.entries()) { + const url = combineURL(ctx.req.baseURL, path); + const checkRE = new RegExp(`^${url}([/?].*)?`); - if (path === '/') { - allMiddlewares.push(...middlewares); - } else if (checkRE.test(ctx.req.url!)) { - allMiddlewares.push(...middlewares); - } + if (path === '/') { + allMiddlewares.push(...middlewares); + } else if (checkRE.test(ctx.req.url!)) { + allMiddlewares.push(...middlewares); } + } - const tasks = [...allMiddlewares, flush]; - return (function next(): Promise { - return tasks.shift()!(ctx, next); - })(); - }; + const tasks = [...allMiddlewares, finish]; + return (function next(): Promise { + return tasks.shift()!(ctx, next); + })(); } } diff --git a/src/core/createInstance.ts b/src/core/createInstance.ts index dc40d3a..a398065 100644 --- a/src/core/createInstance.ts +++ b/src/core/createInstance.ts @@ -68,7 +68,7 @@ export function createInstance(config: AxiosRequestConfig, parent?: Axios) { return createInstance(mergeConfig(instance.defaults, config)); }; instance.extend = function extend(config: AxiosRequestConfig = {}) { - config.url = combineURL(instance.defaults.baseURL, config.url); + config.baseURL = combineURL(instance.defaults.baseURL, config.baseURL); return createInstance(mergeConfig(instance.defaults, config), context); }; instance.fork = instance.extend; diff --git a/test/core/MiddlewareManager.test.ts b/test/core/MiddlewareManager.test.ts deleted file mode 100644 index f615531..0000000 --- a/test/core/MiddlewareManager.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { describe, test, expect, vi } from 'vitest'; -import MiddlewareManager from '@/core/MiddlewareManager'; - -describe('src/core/MiddlewareManager.ts', () => { - test('应该有这些实例属性', () => { - const m = new MiddlewareManager(vi.fn()); - - expect(m.use).toBeTypeOf('function'); - expect(m.wrap).toBeTypeOf('function'); - }); - - test('应该可以添加中间件回调', async () => { - const flush = vi.fn(async (ctx) => { - expect(ctx.req.url).toBe('test'); - ctx.res = res; - }); - const m = new MiddlewareManager(flush); - const ctx = { - req: { url: 'https://api.com' }, - res: null, - }; - const res = { - 'src/core/MiddlewareManager.ts': true, - }; - const midde = vi.fn(async (ctx, next) => { - expect(ctx).toBe(ctx); - ctx.req.url = 'test'; - await next(); - expect(ctx.res).toBe(res); - }); - - m.use(midde); - await m.flush(ctx); - - expect(ctx.res).toBe(res); - expect(midde).toBeCalled(); - }); - - test('应该可以给路径添加中间件回调', async () => { - const flush = vi.fn(async (ctx) => { - ctx.res = res; - }); - - const m = new MiddlewareManager(flush); - const ctx1 = { - req: { - baseURL: 'https://api.com', - url: 'https://api.com', - }, - res: null, - }; - const ctx2 = { - req: { - baseURL: 'https://api.com', - url: 'https://api.com/test', - }, - res: null, - }; - const res = { - 'src/core/MiddlewareManager.ts': true, - }; - const midde = vi.fn(async (ctx, next) => { - expect(ctx).toBe(ctx); - await next(); - expect(ctx.res).toBe(res); - }); - - m.use('/test', midde); - await m.flush(ctx1); - - expect(ctx1.res).toBe(res); - expect(midde).not.toBeCalled(); - - m.use('/test', midde); - await m.flush(ctx2); - - expect(midde).toBeCalled(); - }); -});