Skip to content

Commit

Permalink
fix: router sort with param (#877)
Browse files Browse the repository at this point in the history
  • Loading branch information
czy88840616 committed Mar 1, 2021
1 parent e11a057 commit 7405745
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 12 deletions.
23 changes: 20 additions & 3 deletions packages/core/src/util/webRouterCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,38 @@ export class WebRouterCollector {
}
}

protected sortRouter(urlMatchList: RouterInfo[]) {
public sortRouter(urlMatchList: RouterInfo[]) {
// 1. 绝对路径规则优先级最高如 /ab/cb/e
// 2. 星号只能出现最后且必须在/后面,如 /ab/cb/**
// 3. 如果绝对路径和通配都能匹配一个路径时,绝对规则优先级高
// 4. 有多个通配能匹配一个路径时,最长的规则匹配,如 /ab/** 和 /ab/cd/** 在匹配 /ab/cd/f 时命中 /ab/cd/**
// 5. 如果 / 与 /* 都能匹配 / ,但 / 的优先级高于 /*
return urlMatchList
.map(item => {
const urlString = item.url.toString();
let category = 2;
const paramString = urlString.includes(':')
? urlString.replace(/:.+$/, '')
: '';
if (paramString) {
category = 1;
}
if (urlString.includes('*')) {
category = 0;
}
return {
...item,
_pureRouter: item.url.toString().replace(/\**$/, ''),
_level: item.url.toString().split('/').length - 1,
_pureRouter: urlString.replace(/\**$/, '').replace(/:\w+/, '123'),
_level: urlString.split('/').length - 1,
_paramString: paramString,
_category: category,
};
})
.sort((handlerA, handlerB) => {
// 不同一层级的对比
if (handlerA._category !== handlerB._category) {
return handlerB._category - handlerA._category;
}
if (handlerA._level === handlerB._level) {
if (handlerB._pureRouter === handlerA._pureRouter) {
return (
Expand Down
160 changes: 160 additions & 0 deletions packages/core/test/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
exports.routerList1 = [
{
'prefix': '/swagger-ui',
'routerName': '',
'url': '/*',
'requestMethod': 'get',
'method': 'renderSwagger',
'description': '',
'summary': '',
'handlerName': 'swagger:swaggerController.renderSwagger',
'funcHandlerName': 'swagger:swaggerController.renderSwagger',
'controllerId': 'swagger:swaggerController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
},
{
'prefix': '/swagger-ui',
'routerName': '',
'url': '/abc/*',
'requestMethod': 'get',
'method': 'renderSwagger',
'description': '',
'summary': '',
'handlerName': 'swagger:swaggerController.renderSwagger',
'funcHandlerName': 'swagger:swaggerController.renderSwagger',
'controllerId': 'swagger:swaggerController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
},
{
'prefix': '/swagger-ui',
'routerName': '',
'url': '/:fileName',
'requestMethod': 'get',
'method': 'renderSwagger',
'description': '',
'summary': '',
'handlerName': 'swagger:swaggerController.renderSwagger',
'funcHandlerName': 'swagger:swaggerController.renderSwagger',
'controllerId': 'swagger:swaggerController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
},
{
'prefix': '/swagger-ui',
'routerName': '',
'url': '/:abc/123',
'requestMethod': 'get',
'method': 'renderSwagger',
'description': '',
'summary': '',
'handlerName': 'swagger:swaggerController.renderSwagger',
'funcHandlerName': 'swagger:swaggerController.renderSwagger',
'controllerId': 'swagger:swaggerController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
},
{
'prefix': '/swagger-ui',
'routerName': '',
'url': '/json',
'requestMethod': 'get',
'method': 'renderJSON',
'description': '',
'summary': '',
'handlerName': 'swagger:swaggerController.renderJSON',
'funcHandlerName': 'swagger:swaggerController.renderJSON',
'controllerId': 'swagger:swaggerController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
},
{
'prefix': '/swagger-ui',
'routerName': '',
'url': '/',
'requestMethod': 'get',
'method': 'renderSwagger',
'description': '',
'summary': '',
'handlerName': 'swagger:swaggerController.renderSwagger',
'funcHandlerName': 'swagger:swaggerController.renderSwagger',
'controllerId': 'swagger:swaggerController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
}];

exports.routerList2 = [
{
'prefix': '/',
'routerName': '',
'url': '/update',
'requestMethod': 'patch',
'method': 'update',
'description': '',
'summary': '',
'handlerName': 'homeController.update',
'funcHandlerName': 'homeController.update',
'controllerId': 'homeController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [
{
'index': 1,
'type': 1,
'propertyData': 'common:all_value_key'
}
],
'responseMetadata': [],
'_pureRouter': '/update',
'_level': 1
},
{
'prefix': '/',
'routerName': '',
'url': '/',
'requestMethod': 'post',
'method': 'home',
'description': '',
'summary': '',
'handlerName': 'homeController.home',
'funcHandlerName': 'homeController.home',
'controllerId': 'homeController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
'_pureRouter': '/',
'_level': 1
},
{
'prefix': '/',
'routerName': '',
'url': '/*',
'requestMethod': 'get',
'method': 'home',
'description': '',
'summary': '',
'handlerName': 'homeController.home',
'funcHandlerName': 'homeController.home',
'controllerId': 'homeController',
'middleware': [],
'controllerMiddleware': [],
'requestMetadata': [],
'responseMetadata': [],
'_pureRouter': '/',
'_level': 1
}
];
19 changes: 19 additions & 0 deletions packages/core/test/webRouterCollector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,23 @@ describe('/test/webRouterCollector.test.ts', function () {
const result = await collector.getFlattenRouterTable();
expect(result.length === 2).toBeTruthy();
});

it('should sort param', function () {
const collector = new WebRouterCollector();
const result = collector.sortRouter(require('./router').routerList1);
expect(result[0].url).toEqual('/json');
expect(result[1].url).toEqual('/');
expect(result[2].url).toEqual('/:abc/123');
expect(result[3].url).toEqual('/:fileName');
expect(result[4].url).toEqual('/abc/*');
expect(result[5].url).toEqual('/*');
});

it('should sort wildcard', function () {
const collector = new WebRouterCollector();
const result = collector.sortRouter(require('./router').routerList2);
expect(result[0].url).toEqual('/update');
expect(result[1].url).toEqual('/');
expect(result[2].url).toEqual('/*');
});
});
25 changes: 16 additions & 9 deletions packages/mock/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,32 @@ export type MockAppConfigurationOptions = {
cleanLogsDir?: boolean;
cleanTempDir?: boolean;
entryFile?: string;
baseDir?: string;
};

export async function create<
T extends IMidwayFramework<any, U>,
U = T['configurationOptions']
>(
baseDir: string = process.cwd(),
appDir: string = process.cwd(),
options?: U & MockAppConfigurationOptions,
customFrameworkName?: string | MidwayFrameworkType | any
): Promise<T> {
process.env.MIDWAY_TS_MODE = 'true';
clearAllModule();
clearContainerCache();
clearAllLoggers();
safeRequire(`${baseDir}/src/interface`);

options = options || ({} as any);
if (options.baseDir) {
safeRequire(join(`${options.baseDir}`, 'interface'));
} else {
safeRequire(join(`${appDir}`, 'src/interface'));
}

if (options.entryFile) {
// start from entry file, like bootstrap.js
options.entryFile = formatPath(baseDir, options.entryFile);
options.entryFile = formatPath(appDir, options.entryFile);
global['MIDWAY_BOOTSTRAP_APP_READY'] = false;
// set app in @midwayjs/bootstrap
require(options.entryFile);
Expand Down Expand Up @@ -132,7 +138,7 @@ export async function create<
}
} else {
// find default framework from pkg
const pkg = require(join(baseDir, 'package.json'));
const pkg = require(join(appDir, 'package.json'));
if (pkg.dependencies) {
customFrameworkName = getIncludeFramework(pkg.dependencies);
}
Expand Down Expand Up @@ -168,17 +174,18 @@ export async function create<

const starter = new BootstrapStarter();

if (!isAbsolute(baseDir)) {
baseDir = join(process.cwd(), 'test', 'fixtures', baseDir);
if (!isAbsolute(appDir)) {
appDir = join(process.cwd(), 'test', 'fixtures', appDir);
}

if (!existsSync(baseDir)) {
throw new Error(`${baseDir} not found`);
if (!existsSync(appDir)) {
throw new Error(`${appDir} not found`);
}

starter
.configure({
appDir: baseDir,
appDir,
baseDir: options.baseDir,
})
.load(framework);

Expand Down

0 comments on commit 7405745

Please sign in to comment.