Chi路由器配置中间件时chi.Use与chi.With有何区别
chi.Use 与 chi.With 功能差异及使用说明 在基于Chi路由器开发Web服务、配置中间件的场景下,两个方法都用于挂载中间件,但生效逻辑、适用场景完全不同,具体区别如下:
chi.Use 方法规则
- 核心逻辑:属于路由组全局级别的中间件挂载方法,调用后会直接修改当前路由实例(Router/RouteGroup)的中间件链,没有返回值。
- 生效范围:调用
Use之后,所有注册到当前路由实例、以及该实例下嵌套子路由组的接口,都会自动套用挂载的中间件。 - 执行顺序:遵循洋葱模型,先调用
Use挂载的中间件会先执行,后挂载的包裹在内层执行。 - 代码示例:
r := chi.NewRouter() // 挂载全局通用中间件,后续所有路由都将生效 r.Use(middleware.RequestID) r.Use(middleware.Logger) r.Use(middleware.Recoverer) // 公开接口自动套用上面3个全局中间件 r.Get("/home", HomeHandler) r.Get("/public/notice", NoticeHandler) // 嵌套/api路由组 r.Route("/api", func(r chi.Router) { // 给/api下所有接口追加JSON格式校验中间件 r.Use(middleware.AllowContentType("application/json")) // 该路由执行链:RequestID -> Logger -> Recoverer -> AllowContentType -> 业务逻辑 r.Post("/login", LoginHandler) })
- 适用场景:挂载覆盖范围大的通用横切逻辑,比如全局请求ID生成、访问日志、panic恢复、跨域处理、全局限流等需要作用于整组/全部路由的中间件。
chi.With 方法规则
- 核心逻辑:属于按需追加的临时中间件挂载方法,不会修改原有路由实例的中间件链,只会基于当前实例已有的中间件链,追加传入的新中间件,返回一个全新的路由实例。
- 生效范围:只有在
With返回的新路由实例上注册的接口,才会带上追加的中间件;原有路由实例、以及原有实例上后续注册的其他接口,完全不受影响。 - 执行顺序:新追加的中间件会排在原有中间件链的末尾,同样遵循先挂载先执行的洋葱模型规则。
- 代码示例:
r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.Logger) r.Use(middleware.Recoverer) // 基于全局路由生成带鉴权中间件的新路由实例,原r的中间件链不会被修改 authRouter := r.With(middleware.JWTAuth) // 以下两个注册在authRouter上的接口,会追加JWTAuth校验逻辑 // 执行链:RequestID -> Logger -> Recoverer -> JWTAuth -> 业务逻辑 authRouter.Get("/user/profile", UserProfileHandler) authRouter.Get("/user/orders", UserOrderHandler) // 原r上注册的公开接口不会套用JWTAuth中间件,仍只有3个全局中间件 r.Get("/public/list", PublicListHandler)
- 适用场景:给零散的特定路由组/单接口追加专属中间件,比如给少量需要鉴权的接口加JWT校验、给后台接口追加管理员权限校验、给特定路由加单独的审计日志/限流规则,避免专属中间件污染全局路由链。
核心差异对比
- 对原实例的影响:
Use会直接修改原路由实例的中间件链,是有状态操作;With不会改动原实例,仅生成携带额外中间件的新实例,是无状态操作。 - 作用范围:
Use作用于调用后、当前路由组下注册的所有路由(含嵌套子路由);With仅作用于返回的新实例上注册的路由,不影响原有路由组的任何配置。 - 使用成本:
Use适合批量给整组路由统一配置中间件,代码更简洁;With适合按需给非整组的零散路由追加中间件,灵活性更高,不会产生不必要的中间件性能损耗。
注意:
Use需要在对应路由注册之前调用,否则中间件不会对已注册的路由生效;With生成的新路由实例如果不用于注册路由,追加的中间件不会产生任何效果。
内容的提问来源于stack exchange,提问作者Gurleen Sethi
相关产品推荐
相关产品推荐

