@@ -56,6 +56,7 @@ export class MidwayExpressFramework extends BaseFramework<
5656 debug ( '[express]: create express app' ) ;
5757 this . app = express ( ) as unknown as IMidwayExpressApplication ;
5858 debug ( '[express]: use root middleware' ) ;
59+
5960 // use root middleware
6061 this . app . use ( ( req , res , next ) => {
6162 const ctx = req as Context ;
@@ -66,6 +67,14 @@ export class MidwayExpressFramework extends BaseFramework<
6667 next ( ) ;
6768 } ) ;
6869
70+ // 版本控制配置
71+ const versioningConfig = this . configurationOptions . versioning ;
72+
73+ // 如果启用版本控制,添加版本处理中间件
74+ if ( versioningConfig ?. enabled ) {
75+ this . app . use ( this . createVersioningMiddleware ( versioningConfig ) ) ;
76+ }
77+
6978 this . defineApplicationProperties ( {
7079 useMiddleware : (
7180 routerPath :
@@ -414,4 +423,60 @@ export class MidwayExpressFramework extends BaseFramework<
414423 public getFrameworkName ( ) {
415424 return 'express' ;
416425 }
426+
427+ private createVersioningMiddleware ( config : any ) {
428+ return ( req : Context , res : Response , next : NextFunction ) => {
429+ // 提取版本信息
430+ const version = this . extractVersion ( req , config ) ;
431+ req . apiVersion = version ;
432+
433+ // 对于 URI 版本控制,重写路径
434+ if ( config . type === 'URI' && version ) {
435+ const versionPrefix = `/${ config . prefix || 'v' } ${ version } ` ;
436+ if ( req . path . startsWith ( versionPrefix ) ) {
437+ req . originalPath = req . path ;
438+ // Express 中需要修改 url 而不是 path
439+ req . url = req . url . replace ( versionPrefix , '' ) || '/' ;
440+ }
441+ }
442+
443+ next ( ) ;
444+ } ;
445+ }
446+
447+ private extractVersion ( req : Context , config : any ) : string | undefined {
448+ // 自定义提取函数优先
449+ if ( config . extractVersionFn ) {
450+ return config . extractVersionFn ( req ) ;
451+ }
452+
453+ const type = config . type || 'URI' ;
454+
455+ switch ( type ) {
456+ case 'HEADER' : {
457+ const headerName = config . header || 'x-api-version' ;
458+ const headerValue = req . headers [ headerName ] ;
459+ if ( typeof headerValue === 'string' ) {
460+ return headerValue . replace ( / ^ v / , '' ) ;
461+ }
462+ return undefined ;
463+ }
464+
465+ case 'MEDIA_TYPE' : {
466+ const accept = req . headers . accept ;
467+ const paramName = config . mediaTypeParam || 'version' ;
468+ const match = accept ?. match ( new RegExp ( `${ paramName } =(\\\\d+)` ) ) ;
469+ return match ? match [ 1 ] : undefined ;
470+ }
471+
472+ case 'URI' : {
473+ const prefix = config . prefix || 'v' ;
474+ const uriMatch = req . path . match ( new RegExp ( `^/${ prefix } (\\\\d+)` ) ) ;
475+ return uriMatch ? uriMatch [ 1 ] : undefined ;
476+ }
477+
478+ default :
479+ return config . defaultVersion ;
480+ }
481+ }
417482}
0 commit comments