diff --git a/packages/core/src/service/aspectService.ts b/packages/core/src/service/aspectService.ts index 67054419b3d..fb6b107eba3 100644 --- a/packages/core/src/service/aspectService.ts +++ b/packages/core/src/service/aspectService.ts @@ -80,97 +80,126 @@ export class MidwayAspectService { * @param aspectObject aspect object, before, round, etc. */ public interceptPrototypeMethod( - Clz: new (...args) => any, + Clz: new (...args: any[]) => any, methodName: string, aspectObject: IMethodAspect | (() => IMethodAspect) ) { const originMethod = Clz.prototype[methodName]; if (Types.isAsyncFunction(Clz.prototype[methodName])) { - Clz.prototype[methodName] = async function (...args) { - let error, result; - const newProceed = (...args) => { - return originMethod.apply(this, args); - }; - const joinPoint = { + Clz.prototype[methodName] = async function (...args: unknown[]): Promise { + const opts: ProcessOptions = { + args, methodName, target: this, - args: args, - proceed: newProceed, - proceedIsAsyncFunction: true, - } as JoinPoint; - - if (typeof aspectObject === 'function') { - aspectObject = aspectObject(); - } - - try { - await aspectObject.before?.(joinPoint); - if (aspectObject.around) { - result = await aspectObject.around(joinPoint); - } else { - result = await originMethod.call(this, ...joinPoint.args); - } - joinPoint.proceed = undefined; - const resultTemp = await aspectObject.afterReturn?.( - joinPoint, - result - ); - result = typeof resultTemp === 'undefined' ? result : resultTemp; - return result; - } catch (err) { - joinPoint.proceed = undefined; - error = err; - if (aspectObject.afterThrow) { - await aspectObject.afterThrow(joinPoint, error); - } else { - throw err; - } - } finally { - await aspectObject.after?.(joinPoint, result, error); - } + }; + return processAsync(aspectObject, originMethod, opts); }; } else { - Clz.prototype[methodName] = function (...args) { - let error, result; - const newProceed = (...args) => { - return originMethod.apply(this, args); - }; - const joinPoint = { + Clz.prototype[methodName] = function (...args: unknown[]) { + const opts: ProcessOptions = { + args, methodName, target: this, - args: args, - proceed: newProceed, - proceedIsAsyncFunction: false, - } as JoinPoint; - - if (typeof aspectObject === 'function') { - aspectObject = aspectObject(); - } - - try { - aspectObject.before?.(joinPoint); - if (aspectObject.around) { - result = aspectObject.around(joinPoint); - } else { - result = originMethod.call(this, ...joinPoint.args); - } - joinPoint.proceed = undefined; - const resultTemp = aspectObject.afterReturn?.(joinPoint, result); - result = typeof resultTemp === 'undefined' ? result : resultTemp; - return result; - } catch (err) { - joinPoint.proceed = undefined; - error = err; - if (aspectObject.afterThrow) { - aspectObject.afterThrow(joinPoint, error); - } else { - throw err; - } - } finally { - aspectObject.after?.(joinPoint, result, error); - } + }; + return processSync(aspectObject, originMethod, opts); }; } } } + +interface ProcessOptions { + args: unknown[], + methodName: string; + target: any +} +async function processAsync( + aspectObjectInput: IMethodAspect | (() => IMethodAspect), + originMethod: Function, + options: ProcessOptions +): Promise { + + let error: Error; + let result: unknown; + const newProceed = (...args: unknown[]) => { + return originMethod.apply(this, args); + }; + const joinPoint = Object.assign({}, options, {proceed: newProceed, proceedIsAsyncFunction: true}) as JoinPoint; + + let aspectObject: IMethodAspect; + if (typeof aspectObjectInput === 'function') { + aspectObject = aspectObjectInput(); + } else { + aspectObject = aspectObjectInput; + } + + try { + await aspectObject.before?.(joinPoint); + if (aspectObject.around) { + result = await aspectObject.around(joinPoint); + } else { + result = await originMethod.call(this, ...joinPoint.args); + } + joinPoint.proceed = undefined; + const resultTemp = await aspectObject.afterReturn?.( + joinPoint, + result + ); + result = typeof resultTemp === 'undefined' ? result : resultTemp; + return result; + } catch (err) { + joinPoint.proceed = undefined; + error = err; + if (aspectObject.afterThrow) { + await aspectObject.afterThrow(joinPoint, error); + } else { + throw err; + } + } finally { + await aspectObject.after?.(joinPoint, result, error); + } +} + +function processSync( + aspectObjectInput: IMethodAspect | (() => IMethodAspect), + originMethod: Function, + options: ProcessOptions +): unknown { + + let error: Error; + let result: unknown; + const newProceed = (...args: unknown[]) => { + return originMethod.apply(this, args); + }; + const joinPoint = Object.assign({}, options, {proceed: newProceed, proceedIsAsyncFunction: false}) as JoinPoint; + + let aspectObject: IMethodAspect; + if (typeof aspectObjectInput === 'function') { + aspectObject = aspectObjectInput(); + } else { + aspectObject = aspectObjectInput; + } + + try { + aspectObject.before?.(joinPoint); + if (aspectObject.around) { + result = aspectObject.around(joinPoint); + } else { + result = originMethod.call(this, ...joinPoint.args); + } + joinPoint.proceed = undefined; + const resultTemp = aspectObject.afterReturn?.(joinPoint, result); + result = typeof resultTemp === 'undefined' ? result : resultTemp; + return result; + } catch (err) { + joinPoint.proceed = undefined; + error = err; + if (aspectObject.afterThrow) { + aspectObject.afterThrow(joinPoint, error); + } else { + throw err; + } + } finally { + aspectObject.after?.(joinPoint, result, error); + } +} diff --git a/packages/core/src/service/middlewareService.ts b/packages/core/src/service/middlewareService.ts index 79a030fdfd3..da75a9b30b0 100644 --- a/packages/core/src/service/middlewareService.ts +++ b/packages/core/src/service/middlewareService.ts @@ -91,68 +91,16 @@ export class MidwayMiddlewareService { const composeFn = (context: T, next?) => { const supportBody = isIncludeProperty(context, 'body'); // last called middleware # - let index = -1; - return dispatch(0); - - function dispatch(i) { - if (i <= index) - return Promise.reject( - new MidwayCommonError('next() called multiple times') - ); - index = i; - let fn = (newMiddlewareArr as Array>)[i]; - if (i === newMiddlewareArr.length) fn = next; - if (!fn) return Promise.resolve(); - const middlewareName = `${name ? `${name}.` : ''}${index} ${ - (fn as any)._name || fn.name || 'anonymous' - }`; - const startTime = Date.now(); - debug(`[middleware]: in ${middlewareName} +0`); - try { - if (supportBody) { - return Promise.resolve( - fn(context, dispatch.bind(null, i + 1), { - index, - } as any) - ).then(result => { - /** - * 1、return 和 ctx.body,return 的优先级更高 - * 2、如果 result 有值(非 undefined),则不管什么情况,都会覆盖当前 body,注意,这里有可能赋值 null,导致 status 为 204,会在中间件处进行修正 - * 3、如果 result 没值,且 ctx.body 已经赋值,则向 result 赋值 - */ - if (result !== undefined) { - context['body'] = result; - } else if (context['body'] !== undefined) { - result = context['body']; - } - debug( - `[middleware]: out ${middlewareName} +${ - Date.now() - startTime - } with body` - ); - return result; - }); - } else { - return Promise.resolve( - fn(context, dispatch.bind(null, i + 1), { - index, - } as any) - ).then(result => { - debug( - `[middleware]: out ${middlewareName} +${Date.now() - startTime}` - ); - return result; - }); - } - } catch (err) { - debug( - `[middleware]: out ${middlewareName} +${ - Date.now() - startTime - } with err ${err.message}` - ); - return Promise.reject(err); - } - } + const opts: DispatchOptions = { + context, + i: 0, + index: -1, + name, + newMiddlewareArr, + next, + supportBody, + }; + return dispatch(opts); }; if (name) { composeFn._name = name; @@ -160,3 +108,78 @@ export class MidwayMiddlewareService { return composeFn; } } + +interface DispatchOptions { + context: any; + i: number; + index: number; + name: string; + newMiddlewareArr: unknown[]; + next: FunctionMiddleware; + supportBody: boolean; +} + +function dispatch(options: DispatchOptions): Promise { + const { i, context, newMiddlewareArr, name, next, supportBody } = options; + + if (i <= options.index) { + return Promise.reject( + new MidwayCommonError('next() called multiple times') + ); + } + options.index = i; + let fn = (newMiddlewareArr as Array>)[i]; + if (i === newMiddlewareArr.length) { + fn = next; + } + if (!fn) return Promise.resolve(); + const middlewareName = `${name ? `${name}.` : ''}${options.index} ${ + (fn as any)._name || fn.name || 'anonymous' + }`; + const startTime = Date.now(); + debug(`[middleware]: in ${middlewareName} +0`); + try { + if (supportBody) { + const opts = { ...options, i: i + 1 }; + return Promise.resolve( + fn(context, dispatch.bind(null, opts), { + index: options.index, + } as any) + ).then(result => { + /** + * 1、return 和 ctx.body,return 的优先级更高 + * 2、如果 result 有值(非 undefined),则不管什么情况,都会覆盖当前 body,注意,这里有可能赋值 null,导致 status 为 204,会在中间件处进行修正 + * 3、如果 result 没值,且 ctx.body 已经赋值,则向 result 赋值 + */ + if (result !== undefined) { + context['body'] = result; + } else if (context['body'] !== undefined) { + result = context['body']; + } + debug( + `[middleware]: out ${middlewareName} +${ + Date.now() - startTime + } with body` + ); + return result; + }); + } else { + const opts = { ...options, i: i + 1 }; + return Promise.resolve( + fn(context, dispatch.bind(null, opts), { + index: options.index, + } as any) + ).then(result => { + debug(`[middleware]: out ${middlewareName} +${Date.now() - startTime}`); + return result; + }); + } + } catch (err) { + debug( + `[middleware]: out ${middlewareName} +${ + Date.now() - startTime + } with err ${err.message}` + ); + return Promise.reject(err); + } +}