diff --git a/app.v b/app.v index a6360bc..854c4ce 100644 --- a/app.v +++ b/app.v @@ -40,6 +40,10 @@ pub mut: use_fast_router bool = true // 新增:是否使用快速路由器 context_middlewares []ContextMiddleware route_middlewares map[string][]ContextMiddleware // 路由前缀对应的中间件 + // 优化:预排序的中间件前缀列表(启动时计算一次) + sorted_middleware_prefixes []string + // 优化:标记是否有中间件(用于零中间件快速路径) + has_middlewares bool } // Context 中间件类型 @@ -185,6 +189,14 @@ pub fn (mut app Hono) all(path string, handler fn (mut Context) http.Response) { // Context 中间件 pub fn (mut app Hono) use(mw ContextMiddleware) { app.context_middlewares << mw + app.has_middlewares = true +} + +// 预计算中间件前缀排序(在服务器启动前调用) +pub fn (mut app Hono) precompute_middleware_prefixes() { + app.sorted_middleware_prefixes = app.route_middlewares.keys() + app.sorted_middleware_prefixes.sort(a.len < b.len) + app.has_middlewares = app.context_middlewares.len > 0 || app.route_middlewares.len > 0 } // notFound() - 自定义 404 处理器 @@ -234,12 +246,18 @@ fn (mut s ServerHanler) handle(req http.Request) http.Response { body := req.data // 构造 Context mut ctx := Context.new(req, param_map, query_map, body) + + // 优化:零中间件快速路径 + if !s.app.has_middlewares { + return route_match.handler.handle(mut ctx) + } + // 获取该路径对应的中间件 middlewares := s.get_middlewares_for_path(url.path) // 洋葱模型递归执行中间件 return s.exec_context_middlewares_with_list(0, middlewares, mut ctx, fn [route_match] (mut c Context) http.Response { return route_match.handler.handle(mut c) - }) + }) } // 如果快速路由器没有匹配,回退到混合路由器 @@ -250,6 +268,12 @@ fn (mut s ServerHanler) handle(req http.Request) http.Response { body := req.data // 构造 Context mut ctx := Context.new(req, param_map, query_map, body) + + // 优化:零中间件快速路径 + if !s.app.has_middlewares { + return route_match.handler.handle(mut ctx) + } + // 获取该路径对应的中间件 middlewares := s.get_middlewares_for_path(url.path) // 洋葱模型递归执行中间件 @@ -265,6 +289,12 @@ fn (mut s ServerHanler) handle(req http.Request) http.Response { body := req.data // 构造 Context mut ctx := Context.new(req, param_map, query_map, body) + + // 优化:零中间件快速路径 + if !s.app.has_middlewares { + return route_match.handler.handle(mut ctx) + } + // 获取该路径对应的中间件 middlewares := s.get_middlewares_for_path(url.path) // 洋葱模型递归执行中间件 @@ -291,15 +321,17 @@ fn (mut s ServerHanler) handle(req http.Request) http.Response { }) } -// 获取路径对应的所有中间件(全局 + 路由前缀匹配的) +// 获取路径对应的所有中间件(全局 + 路由前缀匹配的)- 优化版 fn (s ServerHanler) get_middlewares_for_path(path string) []ContextMiddleware { + // 优化:只有全局中间件时,直接返回引用(避免克隆) + if s.app.route_middlewares.len == 0 { + return s.app.context_middlewares + } + mut middlewares := s.app.context_middlewares.clone() - // 按前缀长度排序,确保更具体的前缀后执行 - mut prefixes := s.app.route_middlewares.keys() - prefixes.sort(a.len < b.len) - - for prefix in prefixes { + // 优化:使用预排序的前缀列表(启动时已排序,不需要每次请求都排序) + for prefix in s.app.sorted_middleware_prefixes { if path.starts_with(prefix) || prefix == '/' { if mws := s.app.route_middlewares[prefix] { middlewares << mws @@ -342,6 +374,9 @@ pub fn (mut app Hono) listen(port string) { return } + // 优化:预计算中间件前缀排序 + app.precompute_middleware_prefixes() + // 使用优化配置的 picoev 高性能服务器(支持高并发) app.listen_picoev_with_config(PicoevConfig{ port: port_num @@ -372,6 +407,7 @@ pub fn (mut app Hono) route(prefix string, mut subapp Hono) { } else { app.route_middlewares[prefix] = subapp.context_middlewares.clone() } + app.has_middlewares = true } // 继承子应用的 notFound 和 onError 处理器(如果主应用没有设置) @@ -508,5 +544,7 @@ pub fn Hono.new() Hono { fast_router: FastRouter.new() use_fast_router: true route_middlewares: map[string][]ContextMiddleware{} + sorted_middleware_prefixes: []string{} + has_middlewares: false } } diff --git a/fast_router.v b/fast_router.v index f8fcfe9..4e57f6c 100644 --- a/fast_router.v +++ b/fast_router.v @@ -171,17 +171,18 @@ fn (router FastRouter) precompile_route(method string, handler IHandler) !Precom } } -// 快速路由匹配(优化版:静态路由跳过缓存 + 预分配结果) +// 快速路由匹配(优化版:静态路由跳过缓存 + 预分配结果 + 复用 cache key) pub fn (mut router FastRouter) match_route(method string, path string) ?ContextRouteMatch { + // 优化:只拼接一次 cache key,复用于静态路由和缓存查找 + cache_key := '${method}:${path}' + // 1. 静态路由直接返回预分配的结果(零分配) - static_key := '${method}:${path}' - if result := router.static_route_results[static_key] { + if result := router.static_route_results[cache_key] { return result } // 2. 动态路由先检查 LRU 缓存(避免重复正则匹配) if router.cache_enabled { - cache_key := '${method}:${path}' if cached := router.lru_cache.get(cache_key) { return cached } @@ -208,9 +209,8 @@ pub fn (mut router FastRouter) match_route(method string, path string) ?ContextR base_path: '' } - // 只缓存动态路由结果 + // 只缓存动态路由结果(复用 cache_key) if router.cache_enabled { - cache_key := '${method}:${path}' router.lru_cache.put(cache_key, result) } diff --git a/picoev_server.v b/picoev_server.v index 02ab0eb..730f877 100644 --- a/picoev_server.v +++ b/picoev_server.v @@ -79,7 +79,15 @@ fn picoev_callback(user_data voidptr, req picohttpparser.Request, mut res picoht if ctx.app.use_fast_router { if route_match := ctx.app.fast_router.match_route(method_str, path) { mut hono_ctx := create_picoev_context(req, route_match.params, query_map) - middlewares := get_middlewares_for_path_picoev(ctx.app, path) + + // 优化:零中间件快速路径 + if !ctx.app.has_middlewares { + response := route_match.handler.handle(mut hono_ctx) + send_picoev_response(mut res, hono_ctx, response, keepalive, ctx.config) + return + } + + middlewares := get_middlewares_for_path_picoev_optimized(ctx.app, path) response := exec_middlewares_picoev(0, middlewares, mut hono_ctx, route_match.handler) send_picoev_response(mut res, hono_ctx, response, keepalive, ctx.config) return @@ -89,7 +97,15 @@ fn picoev_callback(user_data voidptr, req picohttpparser.Request, mut res picoht // 回退到混合路由器 if route_match := ctx.app.context_hybrid_router.match_route(method_str, path) { mut hono_ctx := create_picoev_context(req, route_match.params, query_map) - middlewares := get_middlewares_for_path_picoev(ctx.app, path) + + // 优化:零中间件快速路径 + if !ctx.app.has_middlewares { + response := route_match.handler.handle(mut hono_ctx) + send_picoev_response(mut res, hono_ctx, response, keepalive, ctx.config) + return + } + + middlewares := get_middlewares_for_path_picoev_optimized(ctx.app, path) response := exec_middlewares_picoev(0, middlewares, mut hono_ctx, route_match.handler) send_picoev_response(mut res, hono_ctx, response, keepalive, ctx.config) return @@ -129,14 +145,17 @@ fn check_keepalive_request(req picohttpparser.Request) bool { return true // HTTP/1.1 默认 Keep-Alive } -// 获取路径对应的所有中间件 -fn get_middlewares_for_path_picoev(app &Hono, path string) []ContextMiddleware { +// 获取路径对应的所有中间件(优化版:使用预排序的前缀列表) +fn get_middlewares_for_path_picoev_optimized(app &Hono, path string) []ContextMiddleware { + // 优化:只有全局中间件时,直接返回引用(避免克隆) + if app.route_middlewares.len == 0 { + return app.context_middlewares + } + mut middlewares := app.context_middlewares.clone() - mut prefixes := app.route_middlewares.keys() - prefixes.sort(a.len < b.len) - - for prefix in prefixes { + // 优化:使用预排序的前缀列表(启动时已排序,不需要每次请求都排序) + for prefix in app.sorted_middleware_prefixes { if path.starts_with(prefix) || prefix == '/' { if mws := app.route_middlewares[prefix] { middlewares << mws @@ -147,6 +166,11 @@ fn get_middlewares_for_path_picoev(app &Hono, path string) []ContextMiddleware { return middlewares } +// 获取路径对应的所有中间件(保留旧版本兼容) +fn get_middlewares_for_path_picoev(app &Hono, path string) []ContextMiddleware { + return get_middlewares_for_path_picoev_optimized(app, path) +} + // 执行中间件链 fn exec_middlewares_picoev(idx int, middlewares []ContextMiddleware, mut ctx Context, handler IHandler) http.Response { if idx < middlewares.len { diff --git a/router.v b/router.v index 05ff995..e3e5cd5 100644 --- a/router.v +++ b/router.v @@ -208,10 +208,34 @@ pub fn (router ContextHybridRouter) match_static_route(method string, path strin return none } -// Context 版本的动态路径匹配 +// Context 版本的动态路径匹配(保留旧版本兼容) fn (mut router ContextHybridRouter) match_dynamic_route(method string, path string) ?ContextRouteMatch { - // 先检查缓存 cache_key := '${method}:${path}' + return router.match_dynamic_route_with_key(cache_key, method, path) +} + +// Context 版本的主匹配函数(优化版:复用 cache key) +pub fn (mut router ContextHybridRouter) match_route(method string, path string) ?ContextRouteMatch { + // 优化:只拼接一次 cache key + cache_key := '${method}:${path}' + + // 1. 先尝试静态路径匹配(最快) + if cache_key in router.static_routes { + return ContextRouteMatch{ + handler: router.static_routes[cache_key] + params: map[string]string{} + path: path + base_path: '' + } + } + + // 2. 再尝试动态路径匹配(复用 cache_key) + return router.match_dynamic_route_with_key(cache_key, method, path) +} + +// Context 版本的动态路径匹配(优化版:接收预计算的 cache_key) +fn (mut router ContextHybridRouter) match_dynamic_route_with_key(cache_key string, method string, path string) ?ContextRouteMatch { + // 先检查缓存 if cached := router.cache.get(cache_key) { return cached } @@ -240,22 +264,6 @@ fn (mut router ContextHybridRouter) match_dynamic_route(method string, path stri return none } -// Context 版本的主匹配函数 -pub fn (mut router ContextHybridRouter) match_route(method string, path string) ?ContextRouteMatch { - // 1. 先尝试静态路径匹配(最快) - if static_handler := router.match_static_route(method, path) { - return ContextRouteMatch{ - handler: static_handler - params: map[string]string{} - path: path - base_path: '' - } - } - - // 2. 再尝试动态路径匹配 - return router.match_dynamic_route(method, path) -} - // Context 版本的获取所有路由 pub fn (router ContextHybridRouter) get_all_routes() ([]string, []string) { mut static_paths := []string{} diff --git a/tests/test_middleware_optimization.v b/tests/test_middleware_optimization.v new file mode 100644 index 0000000..f07ece0 --- /dev/null +++ b/tests/test_middleware_optimization.v @@ -0,0 +1,355 @@ +// 中间件优化测试 +// 测试三个优化点: +// 1. 零中间件快速路径 +// 2. 中间件预计算(启动时排序) +// 3. 复用 cache key + +import hono +import time +import net.http + +// 测试统计 +struct TestStats { +mut: + total_tests int + passed_tests int + failed_tests int +} + +fn (mut stats TestStats) start_test(test_name string) { + stats.total_tests++ + print('🧪 ${test_name}... ') +} + +fn (mut stats TestStats) pass_test() { + stats.passed_tests++ + println('✅') +} + +fn (mut stats TestStats) fail_test(error string) { + stats.failed_tests++ + println('❌ ${error}') +} + +fn (stats TestStats) print_summary() { + println('\n=== 测试总结 ===') + println('总测试数: ${stats.total_tests}') + println('通过: ${stats.passed_tests}') + println('失败: ${stats.failed_tests}') + if stats.failed_tests == 0 { + println('🎉 所有测试通过!') + } else { + println('⚠️ 有 ${stats.failed_tests} 个测试失败') + } +} + +// 测试1:零中间件快速路径 - has_middlewares 标志 +fn test_zero_middleware_flag(mut stats TestStats) { + stats.start_test('零中间件标志 (has_middlewares)') + + mut app := hono.Hono.new() + + // 新创建的应用应该没有中间件 + if app.has_middlewares { + stats.fail_test('新应用不应该有中间件标志') + return + } + + // 添加中间件后标志应该为 true + app.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response { + return next(mut c) + }) + + if !app.has_middlewares { + stats.fail_test('添加中间件后标志应该为 true') + return + } + + stats.pass_test() +} + +// 测试2:中间件预计算 - sorted_middleware_prefixes +fn test_middleware_precompute(mut stats TestStats) { + stats.start_test('中间件预计算 (sorted_middleware_prefixes)') + + mut app := hono.Hono.new() + + // 添加路由 + app.get('/test', fn (mut c hono.Context) http.Response { + return c.text('test') + }) + + // 创建子应用并添加中间件 + mut sub_app := hono.Hono.new() + sub_app.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response { + return next(mut c) + }) + sub_app.get('/hello', fn (mut c hono.Context) http.Response { + return c.text('hello') + }) + + // 挂载子应用 + app.route('/api', mut sub_app) + + // 预计算前,sorted_middleware_prefixes 应该为空 + if app.sorted_middleware_prefixes.len != 0 { + stats.fail_test('预计算前 sorted_middleware_prefixes 应该为空') + return + } + + // 调用预计算 + app.precompute_middleware_prefixes() + + // 预计算后,sorted_middleware_prefixes 应该包含前缀 + if app.sorted_middleware_prefixes.len == 0 && app.route_middlewares.len > 0 { + stats.fail_test('预计算后 sorted_middleware_prefixes 应该包含前缀') + return + } + + // 验证 has_middlewares 标志 + if app.route_middlewares.len > 0 && !app.has_middlewares { + stats.fail_test('有路由中间件时 has_middlewares 应该为 true') + return + } + + stats.pass_test() +} + +// 测试3:FastRouter cache key 复用 +fn test_fast_router_cache_key_reuse(mut stats TestStats) { + stats.start_test('FastRouter cache key 复用') + + mut router := hono.FastRouter.new() + + // 添加静态路由 + static_handler := hono.ContextHandler{ + path: '/users' + handler: fn (mut c hono.Context) http.Response { + return c.text('users') + } + } + router.add_route('GET', static_handler, '') or { + stats.fail_test('添加静态路由失败') + return + } + + // 添加动态路由 + dynamic_handler := hono.ContextHandler{ + path: '/users/:id' + handler: fn (mut c hono.Context) http.Response { + return c.text('user') + } + } + router.add_route('GET', dynamic_handler, '') or { + stats.fail_test('添加动态路由失败') + return + } + + // 测试静态路由匹配 + if _ := router.match_route('GET', '/users') { + // 成功 + } else { + stats.fail_test('静态路由匹配失败') + return + } + + // 测试动态路由匹配(第一次,会缓存) + if match1 := router.match_route('GET', '/users/123') { + if match1.params['id'] != '123' { + stats.fail_test('参数提取失败') + return + } + } else { + stats.fail_test('动态路由匹配失败') + return + } + + // 测试动态路由匹配(第二次,应该命中缓存) + if match2 := router.match_route('GET', '/users/123') { + if match2.params['id'] != '123' { + stats.fail_test('缓存命中后参数提取失败') + return + } + } else { + stats.fail_test('缓存命中失败') + return + } + + // 验证缓存状态 + _, _, cache_count := router.get_stats() + if cache_count == 0 { + stats.fail_test('缓存应该有条目') + return + } + + stats.pass_test() +} + +// 测试4:HybridRouter cache key 复用 +fn test_hybrid_router_cache_key_reuse(mut stats TestStats) { + stats.start_test('HybridRouter cache key 复用') + + mut router := hono.ContextHybridRouter.new() + + // 添加动态路由 + dynamic_handler := hono.ContextHandler{ + path: '/posts/:id' + handler: fn (mut c hono.Context) http.Response { + return c.text('post') + } + } + router.add_route('GET', dynamic_handler, '') + + // 第一次匹配(无缓存) + if match1 := router.match_route('GET', '/posts/456') { + if match1.params['id'] != '456' { + stats.fail_test('参数提取失败') + return + } + } else { + stats.fail_test('动态路由匹配失败') + return + } + + // 第二次匹配(应该命中缓存) + if match2 := router.match_route('GET', '/posts/456') { + if match2.params['id'] != '456' { + stats.fail_test('缓存命中后参数提取失败') + return + } + } else { + stats.fail_test('缓存命中失败') + return + } + + stats.pass_test() +} + +// 测试5:性能对比 - 有中间件 vs 无中间件 +fn test_middleware_performance_comparison(mut stats TestStats) { + stats.start_test('中间件性能对比') + + // 创建无中间件的路由器 + mut router_no_mw := hono.FastRouter.new() + handler := hono.ContextHandler{ + path: '/api/users/:id' + handler: fn (mut c hono.Context) http.Response { + return c.text('user') + } + } + router_no_mw.add_route('GET', handler, '') or { + stats.fail_test('添加路由失败') + return + } + + // 预热 + for _ in 0 .. 100 { + _ := router_no_mw.match_route('GET', '/api/users/123') or { continue } + } + + // 测试无中间件性能 + iterations := 10000 + start_no_mw := time.now() + for _ in 0 .. iterations { + _ := router_no_mw.match_route('GET', '/api/users/123') or { continue } + } + duration_no_mw := time.since(start_no_mw) + + // 创建有中间件的应用 + mut app_with_mw := hono.Hono.new() + app_with_mw.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response { + return next(mut c) + }) + app_with_mw.get('/api/users/:id', fn (mut c hono.Context) http.Response { + return c.text('user') + }) + app_with_mw.precompute_middleware_prefixes() + + // 预热 + for _ in 0 .. 100 { + _ := app_with_mw.fast_router.match_route('GET', '/api/users/123') or { continue } + } + + // 测试有中间件性能 + start_with_mw := time.now() + for _ in 0 .. iterations { + _ := app_with_mw.fast_router.match_route('GET', '/api/users/123') or { continue } + } + duration_with_mw := time.since(start_with_mw) + + println('') + println(' 📊 无中间件: ${duration_no_mw.milliseconds()}ms (${iterations} 次)') + println(' 📊 有中间件: ${duration_with_mw.milliseconds()}ms (${iterations} 次)') + + // 性能差异不应该太大(路由匹配本身不受中间件影响) + stats.pass_test() +} + +// 测试6:预计算排序正确性 +fn test_precompute_sorting(mut stats TestStats) { + stats.start_test('预计算排序正确性') + + mut app := hono.Hono.new() + + // 添加多个子应用,模拟不同长度的前缀 + mut sub1 := hono.Hono.new() + sub1.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response { + return next(mut c) + }) + sub1.get('/test', fn (mut c hono.Context) http.Response { + return c.text('test') + }) + + mut sub2 := hono.Hono.new() + sub2.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response { + return next(mut c) + }) + sub2.get('/test', fn (mut c hono.Context) http.Response { + return c.text('test') + }) + + mut sub3 := hono.Hono.new() + sub3.use(fn (mut c hono.Context, next fn (mut hono.Context) http.Response) http.Response { + return next(mut c) + }) + sub3.get('/test', fn (mut c hono.Context) http.Response { + return c.text('test') + }) + + // 按不同顺序挂载(长前缀先挂载) + app.route('/api/v1/users', mut sub1) + app.route('/api', mut sub2) + app.route('/api/v1', mut sub3) + + // 预计算 + app.precompute_middleware_prefixes() + + // 验证排序:短前缀应该在前面 + if app.sorted_middleware_prefixes.len >= 2 { + for i in 0 .. app.sorted_middleware_prefixes.len - 1 { + if app.sorted_middleware_prefixes[i].len > app.sorted_middleware_prefixes[i + 1].len { + stats.fail_test('前缀排序不正确:${app.sorted_middleware_prefixes[i]} 应该在 ${app.sorted_middleware_prefixes[i + 1]} 之后') + return + } + } + } + + stats.pass_test() +} + +fn main() { + println('🚀 开始中间件优化测试...\n') + + mut stats := TestStats{} + + // 运行所有测试 + test_zero_middleware_flag(mut stats) + test_middleware_precompute(mut stats) + test_fast_router_cache_key_reuse(mut stats) + test_hybrid_router_cache_key_reuse(mut stats) + test_middleware_performance_comparison(mut stats) + test_precompute_sorting(mut stats) + + // 打印测试总结 + stats.print_summary() +} diff --git a/usockets_server.v b/usockets_server.v index f4c5fad..57194e2 100644 --- a/usockets_server.v +++ b/usockets_server.v @@ -49,6 +49,9 @@ pub fn (mut app Hono) listen_usockets(port int) { // 使用 uSockets 启动服务器(带配置) pub fn (mut app Hono) listen_usockets_with_config(config UsocketsConfig) { + // 优化:预计算中间件前缀排序 + app.precompute_middleware_prefixes() + // 存储到全局变量 g_usockets_app = unsafe { &app } g_usockets_config = config @@ -102,9 +105,16 @@ fn usockets_on_data(s usockets.Socket, data &char, length int) usockets.Socket { if g_usockets_app.use_fast_router { if route_match := g_usockets_app.fast_router.match_route(method, path) { mut hono_ctx := create_usockets_context(method, path, route_match.params, query_map, body) - middlewares := get_middlewares_for_path_usockets(g_usockets_app, path) - response := exec_middlewares_usockets(0, middlewares, mut hono_ctx, route_match.handler) - send_usockets_response(s, hono_ctx, response) + + // 优化1:零中间件快速路径 + if !g_usockets_app.has_middlewares { + response := route_match.handler.handle(mut hono_ctx) + send_usockets_response(s, hono_ctx, response) + } else { + middlewares := get_middlewares_for_path_usockets_optimized(g_usockets_app, path) + response := exec_middlewares_usockets(0, middlewares, mut hono_ctx, route_match.handler) + send_usockets_response(s, hono_ctx, response) + } response_sent = true } } @@ -113,9 +123,16 @@ fn usockets_on_data(s usockets.Socket, data &char, length int) usockets.Socket { if !response_sent { if route_match := g_usockets_app.context_hybrid_router.match_route(method, path) { mut hono_ctx := create_usockets_context(method, path, route_match.params, query_map, body) - middlewares := get_middlewares_for_path_usockets(g_usockets_app, path) - response := exec_middlewares_usockets(0, middlewares, mut hono_ctx, route_match.handler) - send_usockets_response(s, hono_ctx, response) + + // 优化1:零中间件快速路径 + if !g_usockets_app.has_middlewares { + response := route_match.handler.handle(mut hono_ctx) + send_usockets_response(s, hono_ctx, response) + } else { + middlewares := get_middlewares_for_path_usockets_optimized(g_usockets_app, path) + response := exec_middlewares_usockets(0, middlewares, mut hono_ctx, route_match.handler) + send_usockets_response(s, hono_ctx, response) + } response_sent = true } } @@ -216,14 +233,17 @@ fn create_usockets_context(method string, path string, params map[string]string, } } -// 获取路径对应的所有中间件 -fn get_middlewares_for_path_usockets(app &Hono, path string) []ContextMiddleware { +// 获取路径对应的所有中间件(优化版:使用预排序的前缀列表) +fn get_middlewares_for_path_usockets_optimized(app &Hono, path string) []ContextMiddleware { + // 优化2:只有全局中间件时,直接返回引用(避免克隆) + if app.route_middlewares.len == 0 { + return app.context_middlewares + } + mut middlewares := app.context_middlewares.clone() - mut prefixes := app.route_middlewares.keys() - prefixes.sort(a.len < b.len) - - for prefix in prefixes { + // 优化3:使用预排序的前缀列表(启动时已排序,不需要每次请求都排序) + for prefix in app.sorted_middleware_prefixes { if path.starts_with(prefix) || prefix == '/' { if mws := app.route_middlewares[prefix] { middlewares << mws @@ -234,6 +254,11 @@ fn get_middlewares_for_path_usockets(app &Hono, path string) []ContextMiddleware return middlewares } +// 获取路径对应的所有中间件(保留旧版本兼容) +fn get_middlewares_for_path_usockets(app &Hono, path string) []ContextMiddleware { + return get_middlewares_for_path_usockets_optimized(app, path) +} + // 执行中间件链 fn exec_middlewares_usockets(idx int, middlewares []ContextMiddleware, mut ctx Context, handler IHandler) http.Response { if idx < middlewares.len {