Open yuntian001 opened 1 year ago
基类上不建议添加装饰器
基类上不建议添加装饰器
我主要想实现分模块, 比如v1、v2两个版本的api,只要继承不同的基类,在基类上写上前缀和定义好模块的公共中间件, 就可以作用到模块下的所有控制器。
import { Controller } from '@midwayjs/decorator';
import { ReportMiddlewareV1 } from '../middleware/report.v1.middlweare';
@Controller('/v1', { middleware: [ ReportMiddlewareV1 ] })
export class APIController {
}
import { Get, Query } from '@midwayjs/decorator';
import { APIController } from './api.controller';
import { ReportMiddlewareV1User } from '../middleware/report.v1.uer.middlweare';
@Controller('/user',{middleware: [ ReportMiddlewareV1User ]});
export class UserController extends APIController {
@Get('/user')
async getUser(@Query('uid') uid) {
return { success: true, message: 'OK', data: {aa:1} };
}
}
期望的访问地址为:/v1/user
,期望应用的中间为["ReportMiddlewareV1","ReportMiddlewareV1User"]
import { Controller } from '@midwayjs/decorator';
import { ReportMiddlewareV2 } from '../middleware/report.v2.middlweare';
@Controller('/v2', { middleware: [ ReportMiddlewareV2 ] })
export class APIController {
}
import { Get, Query } from '@midwayjs/decorator';
import { APIController } from './api.controller';
import { ReportMiddlewareV2User } from '../middleware/report.v2.user.middlweare';
@Controller('/user',{middleware: [ ReportMiddlewareV2User ]});
export class UserController extends APIController {
@Get('/user')
async getUser(@Query('uid') uid) {
return { success: true, message: 'OK', data: {aa:1} };
}
}
期望的访问地址为:/v2/user
,期望应用的中间为["ReportMiddlewareV2","ReportMiddlewareV2User"]
我看官方的 packages\core\src\service\webRouterService.ts
下的路由注册部分
protected analyzeController() {
const controllerModules = listModule(CONTROLLER_KEY);
for (const module of controllerModules) {
const controllerOption: ControllerOption = getClassMetadata(
CONTROLLER_KEY,
module
);
this.addController(
module,
controllerOption,
this.options.includeFunctionRouter
);
}
}
改为获取到controllerOption后递归拿下原型的controllerOption,然后加个@Controller入参控制下是否合并祖先的属性,进行controllerOption合并后再注册,应该可以实现。
不知道官方有没有更好的实现方式和建议
可以试试把不同版本的中间件合并为一个入口,通过 ctx.path 来调用不同版本(中间件)逻辑
可以试试把不同版本的中间件合并为一个入口,通过 ctx.path 来调用不同版本(中间件)逻辑
那样只解决了中间件的问题,前缀问题依然没有解决,而且每次请求都会进行判断,不像注册时只会执行一次。我还在自己封个装饰器,动态注册路由吧。
import {
Provide,
Get,
Configuration,
App,
Inject,
Middleware,
Init,
} from '@midwayjs/decorator';
import * as koa from '@midwayjs/koa';
import { join } from 'path';
import { MidwayWebRouterService } from '@midwayjs/core';
@Provide()
export class HomeController {
@Inject()
ctx;
@Get('/')
async home(): Promise<string> {
return 'Hello Midwayjs!' + this.ctx.user;
}
}
@Middleware()
export class CustomMiddleware {
resolve() {
return async (ctx, next) => {
ctx.user = 'v1';
await next();
};
}
}
@Middleware()
export class CustomMiddleware2 {
resolve() {
return async (ctx, next) => {
ctx.user = 'v2';
await next();
};
}
}
@Configuration({
imports: [koa],
importConfigs: [join(__dirname, './config')],
})
export class ContainerLifeCycle {
@App()
app: koa.Application;
@Inject()
webRouterService: MidwayWebRouterService;
@Init()
async init() {
this.webRouterService.addController(HomeController, {
prefix: '/v1',
routerOptions: {
middleware: [CustomMiddleware],
},
});
this.webRouterService.addController(HomeController, {
prefix: '/v2',
routerOptions: {
middleware: [CustomMiddleware2],
},
});
}
}
//packages\core\src\service\webRouterService.ts
protected mergeControllerOption(controllerOption: ControllerOption, controllerClz: Object) {
if(controllerOption.mergeAncestor){
const prototype = Object.getPrototypeOf(controllerClz);
const parentOption: ControllerOption = getClassMetadata(
CONTROLLER_KEY,
prototype
)
if(parentOption){
controllerOption.prefix = (controllerOption.prefix+parentOption.prefix).replace(/\/\//g,'/');
controllerOption.routerOptions = merge(controllerOption.routerOptions,parentOption.routerOptions);
return this.mergeControllerOption(controllerOption,prototype)
}
}
return controllerOption;
}
protected analyzeController() {
const controllerModules = listModule(CONTROLLER_KEY);
for (const module of controllerModules) {
const controllerOption: ControllerOption = this.mergeControllerOption(getClassMetadata(
CONTROLLER_KEY,
module
),module);
this.addController(
module,
controllerOption,
this.options.includeFunctionRouter
);
}
}
@czy88840616 这种方式是否合适,如果感觉合适我可以完善下提个PR
暂时不建议动原型链,原型链会有不少悖论和延展的问题,比如重名的装饰器是组合还是继承,配置如何处理,swagger 扩展等等。
暂时不建议动原型链,原型链会有不少悖论和延展的问题,比如重名的装饰器是组合还是继承,配置如何处理,swagger 扩展等等。
好的,希望官方能规划出更方便的分模化方案。
比如
这时候路由
/api/user
并不存在。 经测试在nestjs
中这样写是可以访问/api/user
的。