Ocelot 中间件注入实战:通过 OcelotPipelineConfiguration 扩展与覆盖 API 网关管道
发布时间:2026/9/25 3:43:54来源:尧图网络
API网关后端微服务【免费下载链接】Ocelot.NET API Gateway项目地址https://gitcode.com/gh_mirrors/oc/Ocelot点击查看免费下载Ocelot 作为 .NET 的 API 网关其内部以 ASP.NET Core 中间件管道的方式处理每一个上游请求。默认管道内置了路由、安全、限流、认证授权、负载均衡、缓存、请求转发等 24 个环节但默认实现并不总能满足所有业务场景。Ocelot 为此提供了中间件注入机制通过OcelotPipelineConfiguration对象你可以在管道的关键节点插入自定义逻辑甚至可以完全替换掉 Ocelot 内置的认证、授权、响应等中间件。阅读本文后你将掌握app.UseOcelot(pipeline)的完整用法、全部可覆盖节点的语义与执行位置并能基于源码与官方示例落地自定义中间件。一、为什么需要中间件注入Ocelot 的管道对绝大多数请求是黑盒请求进入网关后依次经过配置加载、错误处理、路由查找、安全策略、限流、认证、授权、响应头转换、负载均衡、缓存与请求转发等环节。当你需要在这些环节之间插入自己的逻辑时例如在认证之前校验自定义 Token、在下游响应返回前追加统一响应头、或整体替换响应写出逻辑有两条路把逻辑塞进现有的委托处理程序Delegating Handler但它只能影响发往下游的请求环节使用 Ocelot 提供的中间件注入在管道既定位置上注册自定义中间件函数或在更细粒度上直接覆盖 Ocelot 内置中间件。后者正是本文主题。它的入口非常简单在Program.cs的最后一个配置阶段构造一个OcelotPipelineConfiguration并传给UseOcelot。二、快速上手在 Program.cs 中注入自定义中间件中间件注入只能在应用构建与执行的最终阶段进行。官方文档给出的最小可用形态如下// Set it up: configuration, services, etc. // Middleware setup is only possible during the final stage of app configuration and execution var app builder.Build(); var pipeline new OcelotPipelineConfiguration { PreErrorResponderMiddleware async (context, next) { await next.Invoke(); } }; await app.UseOcelot(pipeline); await app.RunAsync();在上面的例子中PreErrorResponderMiddleware提供的函数会先于 Ocelot 管道的第一块中间件执行——准确地说它位于全局异常处理中间件之后、响应中间件之前。由于每个注入项都是FuncHttpContext, FuncTask, Task形式的委托你可以在next.Invoke()前后分别放置前处理与后处理逻辑从而实现在管道执行前读取/改写HttpContext如注入自定义请求头、记录开始时间在管道执行后观察或改写响应如记录耗时、统一追加响应头。⚠️ 警告注入行为意味着你可以破坏一切——请自行承担风险或享受其乐趣。如果你在中间件管道中发现了任何异常或奇怪行为并且正在使用下述任一注入项请先移除你的自定义中间件再行排查。这一模式在仓库示例中已有完整落地samples/Metadata/Program.cs在构建应用后构造配置对象同时注入了PreErrorResponderMiddleware与ResponderMiddleware两个委托其中ResponderMiddleware还带注释can be switched off/on演示了按需启停内置中间件覆盖的能力。三、OcelotPipelineConfiguration类详解OcelotPipelineConfiguration定义在 src/Middleware/OcelotPipelineConfiguration.cs是所有可注入点的承载对象。它的每个属性都是一个委托或类型管道构建器见第五节会在对应位置决定用你的实现还是用默认实现。完整的可注入点如下表中间件Middleware位置关系说明PreErrorResponderMiddleware前ExceptionHandlerMiddleware后ResponderMiddleware在全局错误处理中间件之后被调用因此next.Invoke之前的所有代码是 Ocelot 管道中执行的下一个动作next.Invoke之后的所有代码是进入全局错误处理器之前管道执行的最后一个动作ResponderMiddleware前PreErrorResponderMiddleware后DownstreamRouteFinderMiddleware允许完全覆盖 Ocelot 的ResponderMiddleware源码见 src/Responder/Middleware/ResponderMiddleware.cs¹PreAuthenticationMiddleware前RequestIdMiddleware后AuthenticationMiddleware允许在 Ocelot 认证真正生效前运行任何额外的认证逻辑AuthenticationMiddleware前PreAuthenticationMiddleware后ClaimsToClaimsMiddleware允许完全覆盖 Ocelot 的AuthenticationMiddleware源码见 src/Authentication/Middleware/AuthenticationMiddleware.cs¹PreAuthorizationMiddleware前ClaimsToClaimsMiddleware后AuthorizationMiddleware允许在 Ocelot 授权真正生效前运行任何额外的授权逻辑AuthorizationMiddleware前PreAuthorizationMiddleware后ClaimsToHeadersMiddleware允许完全覆盖 Ocelot 的AuthorizationMiddleware源码见 src/Authorization/Middleware/AuthorizationMiddleware.cs¹ClaimsToHeadersMiddleware前AuthorizationMiddleware后PreQueryStringBuilderMiddleware允许完全覆盖 Ocelot 的ClaimsToHeadersMiddleware源码见 src/Headers/Middleware/ClaimsToHeadersMiddleware.cs¹PreQueryStringBuilderMiddleware前ClaimsToHeadersMiddleware后ClaimsToQueryStringMiddleware允许实现自己的查询字符串Query String处理逻辑WebSocketsMiddleware²仅作用于 WebSockets 请求分支管道允许完全覆盖 Ocelot 的WebSocketsProxyMiddleware源码见 src/WebSockets/WebSocketsProxyMiddleware.cs¹当WebSocketsMiddlewareType同时被设置时本委托被忽略WebSocketsMiddlewareType²仅作用于 WebSockets 请求分支管道允许指定一个派生自WebSocketsProxyMiddleware的Type作为自定义 WebSockets 代理中间件¹当两个属性同时设置时本选项优先适合定制诸如缓冲区大小等行为参见 docs/features/websockets.rst 中ws-sample一节的示例MapWhenOcelotPipeline管道构建期一个DictionaryFuncHttpContext, bool, ActionIApplicationBuilder集合允许按条件把请求分支到不同的 Ocelot 子管道分支在SecurityMiddleware之后展开关于表内两处脚注必须再三强调⚠️ ¹ 使用上述覆盖项时务必谨慎被覆盖的中间件将移除默认实现。如果你在管道中遇到任何异常或奇怪行为请移除被覆盖的中间件后重试。 ² 覆盖WebSocketsProxyMiddleware的能力自 Ocelot 版本 25.0 起可用。自该版本起UseOcelot构建 Ocelot 管道时会自动调用app.UseWebSockets()24.x 及更早版本需要手动调用。从源码看每个委托属性的类型都是FuncHttpContext, FuncTask, Task第一个参数是当前请求上下文第二个参数是调用下一个中间件的委托返回Task。这与你手写 ASP.NET Core 中间件委托的签名完全一致学习成本很低。四、注入的边界与正确使用姿势文档明确给出了两个边界约束使用前务必理解覆盖必须在app.UseOcelot之前生效。你可以像普通调用一样把上述覆盖项作为参数传给UseOcelot但不能在UseOcelot之后再把它们追加进管道——Ocelot 不会根据指定中间件配置调用后续的中间件覆盖因此事后追加的中间件不会影响 Ocelot 配置。区分系统中间件与用户中间件。HttpRequesterMiddleware等系统中间件是私有、不可覆盖的上表中的公开中间件则完全可定制、可覆盖。不要把二者混为一谈。另外虽然OcelotPipelineConfiguration还暴露了MapWhenOcelotPipeline按条件分支到不同 Ocelot 管道内部 TODO 注释也提示该数据结构待改进但文档表内列出的常规注入点仍以上述 10 个委托/类型为主实际使用时建议按需取用而不是一次注入过多。五、Ocelot 管道构建器BuildOcelotPipeline与UseIfNotNull机制所有注入点的落地都在Ocelot.Middleware.OcelotPipelineExtensions.BuildOcelotPipeline(IApplicationBuilder, OcelotPipelineConfiguration)中完成实现见 src/Middleware/OcelotPipelineExtensions.cs。该方法是整个 Ocelot 管道的封装器其核心是三个UseIfNotNull辅助方法// 普通委托非空则注册否则什么都不做 public static IApplicationBuilder UseIfNotNull(this IApplicationBuilder builder, FuncHttpContext, FuncTask, Task middleware) middleware ! null ? builder.Use(middleware) : builder; // 泛型覆盖非空则注册你的实现否则注册默认 TMiddleware public static IApplicationBuilder UseIfNotNullTMiddleware(this IApplicationBuilder builder, FuncHttpContext, FuncTask, Task middleware, bool addDefault true) where TMiddleware : OcelotMiddleware middleware ! null ? builder.Use(middleware) : addDefault ? builder.UseMiddlewareTMiddleware() : builder; // 类型覆盖校验派生关系后注册指定 Type public static IApplicationBuilder UseIfNotNullTMiddlewareBase(this IApplicationBuilder builder, Type middlewareType) where TMiddlewareBase : OcelotMiddleware { if (middlewareType is null) return builder; if (!middlewareType.BaseType.Equals(typeof(TMiddlewareBase))) throw new Exception($Unable to start Ocelot: error injecting {middlewareType.FullName}, since its base type is not a(n) {typeof(TMiddlewareBase).FullName}!); return builder.UseMiddleware(middlewareType); }这套机制直接回答了覆盖是如何生效的委托形式的注入如PreAuthenticationMiddleware、PreErrorResponderMiddleware走第一个重载你给了实现就用你的没给就完全跳过可覆盖的内置中间件如ResponderMiddleware、AuthenticationMiddleware、AuthorizationMiddleware、ClaimsToHeadersMiddleware走第二个重载你给了实现就用你的没给就回退到默认中间件保证默认管道不受影响类型形式的注入WebSocketsMiddlewareType走第三个重载启动时校验该类型必须继承自WebSocketsProxyMiddleware否则 Ocelot 直接抛出Unable to start Ocelot: error injecting ...异常拒绝启动避免在运行时才发现类型错误。而UseOcelot本身见 src/Middleware/OcelotMiddlewareExtensions.cs提供多个重载无参版本会使用空配置调用UseOcelot(new OcelotPipelineConfiguration())还有ActionOcelotPipelineConfiguration与ActionIApplicationBuilder, OcelotPipelineConfiguration形式方便你在构建管道时对IApplicationBuilder做额外编排。UseOcelot在真正构建管道前还会先完成配置加载CreateConfiguration与诊断监听器OcelotDiagnosticListener的装配。六、管道执行顺序全景BuildOcelotPipeline按以下顺序注册中间件。带星号*的节点是可覆盖的用户中间件即第三节表中的公开注入点不带星号的是系统中间件ConfigurationMiddlewareExceptionHandlerMiddlewarePreErrorResponderMiddleware*ResponderMiddleware*DownstreamRouteFinderMiddlewareMultiplexingMiddlewareSecurityMiddlewareHttpHeadersTransformationMiddlewareDownstreamRequestInitialiserMiddlewareRateLimitingMiddlewareRequestIdMiddlewarePreAuthenticationMiddleware*AuthenticationMiddleware*ClaimsToClaimsMiddlewarePreAuthorizationMiddleware*AuthorizationMiddleware*ClaimsToHeadersMiddleware*PreQueryStringBuilderMiddleware*ClaimsToQueryStringMiddlewareClaimsToDownstreamPathMiddlewareLoadBalancingMiddlewareDownstreamUrlCreatorMiddlewareOutputCacheMiddlewareHttpRequesterMiddleware其中最后一个中间件是HttpRequesterMiddleware如果管道中还存在后续中间件它会调用next但它本身属于 Ocelot 内部实现不在可覆盖的公开中间件列表内因此它既是 Ocelot 管道也是 ASP.NET 管道中的最后一个中间件专职处理非用户操作真正向下游发起请求。最后一个可覆盖的用户中间件是PreQueryStringBuilderMiddleware它从管道配置对象中读取即第三节表内第 8 行。这套顺序在单元测试 unit/Middleware/OcelotPipelineExtensionsTests.cs 中得到直接验证Should_set_up_pipeline测试断言构建后的管道首尾分别为ConfigurationMiddleware索引 0与HttpRequesterMiddleware索引 21并确认注册了 22 个中间件组件Should_expand_pipeline测试则验证MapWhenOcelotPipeline分支在SecurityMiddleware索引 8位置展开。补充一个源码细节WebSockets 请求并不走上述主列表。BuildOcelotPipeline会先app.UseWebSockets()再用MapWhen(context context.WebSockets.IsWebSocketRequest, ...)将 WebSockets 升级请求分支到独立的ConfigureWebSockets管道其内部为DownstreamRouteFinder → Multiplexing → Security → DownstreamRequestInitialiser → LoadBalancing → DownstreamUrlCreator → WebSocketsProxyMiddleware这也是为什么 WebSockets 注入点独立成表的原因。七、UseOcelot前后的 ASP.NET 管道扩展谨慎使用考虑到PreQueryStringBuilderMiddleware与HttpRequesterMiddleware分别是最后一个用户中间件与系统中间件管道内已没有其他 Ocelot 组件。但你仍然可以扩展 ASP.NET 管道本身例如await app.UseOcelot(); app.UseMiddlewareMyCustomMiddleware();不过官方并不推荐在调用UseOcelot()前后添加自定义中间件因为这会影响整个管道的稳定性且该做法未经过测试。这种自定义管道构建方式超出了 Ocelot 管道模型最终方案质量由你自己负责。仓库的验收测试Should_fix_issue_237见 acceptance/MiddlewareInjection/CustomMiddlewareTests.cs恰好演示了这一边界用法它通过app.UseMiddlewareFakeMiddleware(callback).UseOcelot()在 Ocelot 管道之前挂载自定义中间件并利用Response.OnCompleted回调在响应结束后观察状态码——同时注释也坦诚说明目前这种钩子无法改写响应内容只能借助OnCompleted回调。八、实战示例在 Metadata 示例中组合注入两个中间件仓库的 Metadata 示例samples/Metadata/Program.cs是理解注入用法的绝佳范本。它先通过AddOcelot注册服务、替换默认的IHttpResponder然后在构建应用后这样注入var app builder.Build(); var configuration new OcelotPipelineConfiguration { PreErrorResponderMiddleware MyMiddlewares.PreErrorResponderMiddleware, ResponderMiddleware MyMiddlewares.ResponderMiddleware, // can be switched off/on }; await app.UseOcelot(configuration); await app.RunAsync();对应的实现samples/Metadata/MyMiddlewares.cs展示了两种典型的中间件写法PreErrorResponderMiddleware先await next.Invoke()让下游响应先落定再通过context.Items.DownstreamRoute()读取路由元数据route.GetMetadataT按路由做差异化后处理读取插件参数、解析响应 JSON 等ResponderMiddleware保留默认行为的覆盖写法——先从HttpContext.RequestServices取出IHttpResponder、IOcelotLoggerFactory、IErrorsToHttpStatusCodeMapper然后手动实例化默认的Responder.Middleware.ResponderMiddleware并调用其Invoke(context)相当于在自定义包装内复用官方实现最后再补充自己的逻辑。这个模式值得记住当你想在默认中间件周围加点东西而不是彻底替换时可以像示例一样实例化默认中间件并调用它而不是完全重写其内部逻辑。九、实战示例自定义 WebSockets 代理中间件Type 与委托两种方式自 Ocelot 25.0 起你可以用WebSocketsMiddlewareType指定一个继承自WebSocketsProxyMiddleware的中间件类型。WebSockets 章节docs/features/websockets.rst 的ws-sample一节给出的经典场景是自定义缓冲区大小比如面向 HTTP.sys 视频流的高吞吐场景把缓冲提到 64 KBpublic class MyWebSocketsProxyMiddleware : WebSocketsProxyMiddleware { protected override int BufferSize 65536; // 64 KB for high-throughput streams (e.g. HTTP.sys video streaming) public MyWebSocketsProxyMiddleware(RequestDelegate next, IOcelotLoggerFactory logging, IWebSocketsFactory factory) : base(next, logging, factory) { } }然后通过类型注册var wsPipeline new OcelotPipelineConfiguration { WebSocketsMiddlewareType typeof(MyWebSocketsProxyMiddleware), }; await app.UseOcelot(wsPipeline);也可以改用委托形式注册。仓库示例 samples/WebSocket/Program.cs 同时演示了两种方式并刻意同时设置以说明优先级var wsPipeline new OcelotPipelineConfiguration { WebSocketsMiddlewareType typeof(MyWebSocketsProxyMiddleware), // prioritized WebSocketsMiddleware CustomWebSocketsProxyMiddleware, // ignored in favor of the *Type option }; await app.UseOcelot(wsPipeline); // IF Ocelot version is 25.0 and greater, internally called app.UseWebSockets()其中委托版本的实现就是在委托内从RequestServices取出依赖、new 出自定义中间件实例再Invoke它static Task CustomWebSocketsProxyMiddleware(HttpContext context, FuncTask next) { Task Next(HttpContext ctx) next(); var loggerFactory context.RequestServices.GetRequiredServiceIOcelotLoggerFactory(); var factory context.RequestServices.GetRequiredServiceIWebSocketsFactory(); var middleware new MyWebSocketsProxyMiddleware(Next, loggerFactory, factory); return middleware.Invoke(context); }关于两者的优先级文档语义是当WebSocketsMiddlewareType与WebSocketsMiddleware同时设置时Type 优先、委托被忽略。从源码看src/Middleware/OcelotPipelineExtensions.cs 的ConfigureWebSocketsType 总是先于委托注册委托仅当 Type 为 null 时才作为默认实现兜底单元测试ConfigureWebSockets_WithWebSocketsMiddlewareType_AndWebSocketsMiddleware_ShouldPreferType也验证了 Type 注册在前的事实。因此实际使用时二选一即可同时设置只会带来困惑。十、测试与验证这些注入点是如何被保障的仓库为中间件注入提供了双层测试保障可作为你自行验证的参照验收测试acceptance/MiddlewareInjection/CustomMiddlewareTests.cs 中的Should_call_*_middleware系列测试逐一验证PreErrorResponderMiddleware、PreAuthenticationMiddleware、AuthenticationMiddleware、PreAuthorizationMiddleware、AuthorizationMiddleware、PreQueryStringBuilderMiddleware注入后均被实际调用计数器 1并验证请求仍返回 200Should_not_throw_when_pipeline_terminates_early还验证了在PreQueryStringBuilderMiddleware中不调用next、提前终止管道时不会抛异常。单元测试unit/Middleware/OcelotPipelineExtensionsTests.cs 覆盖UseIfNotNull的四种组合null/有效委托、泛型默认/自定义、addDefault: false、Type 空/有效/非法、MapWhenOcelotPipeline分支展开、以及ConfigureWebSockets在默认/Type/委托/两者同时设置四种情况下的注册结果其中非法类型注入会断言抛出Unable to start Ocelot: error injecting ...异常。这两层测试既证明了注入点确实生效也证明了没注入时默认管道完好无损。十一、Roadmap 与社区演进Ocelot 社区对增加更多可覆盖中间件持续表现出兴趣。文档提及的典型请求是 PR 1497——该请求可能出现在后续某个版本中具体是否合入以仓库实际发布为准。无论如何如果现有的可覆盖中间件仍不能满足你的管道灵活性需求官方建议在仓库的 Discussions 中发起新话题讨论。从当前源码结构看可覆盖节点的增加路径是清晰的在OcelotPipelineConfiguration中新增委托/类型属性并在BuildOcelotPipeline的对应位置用UseIfNotNull接入即可这也是社区 PR 常见的改动模式。总结何时使用中间件注入一句话总结选择策略想在认证前多校验一步、在授权前多检查一重、在查询字符串构建阶段做自定义改写 → 用对应的Pre*注入委托零风险、可随时移除想彻底替换响应写出、认证、授权、Claims 转 Headers 或 WebSockets 代理行为 → 用对应覆盖项但必须意识到默认实现会被移除出问题时先移除覆盖再排查想给 WebSockets 代理定制缓冲区等内部行为 → 优先用WebSocketsMiddlewareType子类化WebSocketsProxyMiddleware想在UseOcelot前后挂自定义 ASP.NET 中间件 → 技术上可行但官方不推荐管道稳定性自负。中间件注入是 Ocelot 在开箱即用与深度定制之间给出的平衡点默认管道不动一分一毫需要时在既定位置上精准插入你的逻辑这就是它在生产网关场景中的核心价值。赞分享API网关后端微服务【免费下载链接】Ocelot.NET API Gateway项目地址https://gitcode.com/gh_mirrors/oc/Ocelot点击查看免费下载相关推荐Ocelot 入门与实践基于 ASP.NET Core 中间件管线的 .NET API 网关Ocelot 入门与实践基于 ASP.NET Core 中间件管线的 .NET API 网关 导读 Ocelot 是一个面向 .NET 生态的 API 网关API网关后端微服务gh_mirrors/da/date性能优化指南高效时间计算的7个最佳实践gh_mirrors/da/date性能优化指南高效时间计算的7个最佳实践 在C开发中时间计算的效率直接影响应用性能。gh_mirrors/da/datOcelot 架构全景.NET API 网关的中间件管道、请求流转与部署形态Ocelot 架构全景.NET API 网关的中间件管道、请求流转与部署形态 导读 Ocelot 是为 .NET 生态打造的 API 网关目标用户是运行在API网关后端微服务上一篇MicaForEveryone安装与配置从Microsoft Store到GitHub Releases的完整指南下一篇XCOM 2模组管理器终极指南5步掌握AML启动器高效管理技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网