让 Ocelot 与 asp.net core “共存”
让 Ocelot 与 asp.net core “共存”
Intro#
我们的 API 之前是一个单体应用,各个模块的服务是通过 Assembly 集成在一起,最后部署在一个 web server 下的。
我们已经在拆分服务并且在 Ocelot 的基础上封装了我们自己的网关,但是服务还没有完全拆分,于是有这么一个需求,对于 Ocelot 配置的路由去交给 Ocelot 去转发到真正的服务地址,而那些 Ocelot 没有定义的路由则让交给 AspNetCore
去处理。
实现原理#
实现原理是让 Ocelot 作为一个动态分支路由,只有当 Ocelot 配置了对应路由的下游地址才走 Ocelot 的分支,才把请求交给 Ocelot 处理。
我们可以使用 MapWhen
来处理,接下来就需要知道怎么样判断 Ocelot
是否配置了某一个路由,Ocelot 内部的处理管道,在向下游请求之前是要找到对应匹配的下游路由,所以我们去看一看 Ocelot 的源码,看看 Ocelot 内部是怎么找下游路由的,Ocelot 找下游路由中间件源码
public async Task Invoke(DownstreamContext context)
{
var upstreamUrlPath = context.HttpContext.Request.Path.ToString();
var upstreamQueryString = context.HttpContext.Request.QueryString.ToString();
var upstreamHost = context.HttpContext.Request.Headers["Host"];
Logger.LogDebug($"Upstream url path is {upstreamUrlPath}");
var provider = _factory.Get(context.Configuration);
// 获取下游路由
var downstreamRoute = provider.Get(upstreamUrlPath, upstreamQueryString, context.HttpContext.Request.Method, context.Configuration, upstreamHost);
if (downstreamRoute.IsError)
{
Logger.LogWarning($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
SetPipelineError(context, downstreamRoute.Errors);
return;
}
var downstreamPathTemplates = string.Join(", ", downstreamRoute.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));
Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
context.TemplatePlaceholderNameAndValues = downstreamRoute.Data.TemplatePlaceholderNameAndValues;
await _multiplexer.Multiplex(context, downstreamRoute.Data.ReRoute, _next);
}
通过上面的源码,我们就可以判断 Ocelot 是否有与请求相匹配的下游路由信息
实现#
既然找到了 Ocelot 如何找下游路由,就先给 Ocelot 加一个扩展吧,实现代码如下,Ocelot 扩展完整代码
public static IApplicationBuilder UseOcelotWhenRouteMatch(this IApplicationBuilder app,
Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction)
=> UseOcelotWhenRouteMatch(app, builderAction, new OcelotPipelineConfiguration());
public static IApplicationBuilder UseOcelotWhenRouteMatch(this IApplicationBuilder app,
Action<OcelotPipelineConfiguration> pipelineConfigurationAction,
Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction)
{
var pipelineConfiguration = new OcelotPipelineConfiguration();
pipelineConfigurationAction?.Invoke(pipelineConfiguration);
return UseOcelotWhenRouteMatch(app, builderAction, pipelineConfiguration);
}
public static IApplicationBuilder UseOcelotWhenRouteMatch(this IApplicationBuilder app, Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction, OcelotPipelineConfiguration configuration)
{
app.MapWhen(context =>
{
// 获取 OcelotConfiguration
var internalConfigurationResponse =
context.RequestServices.GetRequiredService<IInternalConfigurationRepository>().Get();
if (internalConfigurationResponse.IsError || internalConfigurationResponse.Data.ReRoutes.Count == 0)
{
// 如果没有配置路由信息,不符合分支路由的条件,直接退出
return false;
}
var internalConfiguration = internalConfigurationResponse.Data;
var downstreamRouteFinder = context.RequestServices
.GetRequiredService<IDownstreamRouteProviderFactory>()
.Get(internalConfiguration);
// 根据请求以及上面获取的Ocelot配置获取下游路由
var response = downstreamRouteFinder.Get(context.Request.Path, context.Request.QueryString.ToString(),
context.Request.Method, internalConfiguration, context.Request.Host.ToString());
// 如果有匹配路由则满足该分支路由的条件,交给 Ocelot 处理
return !response.IsError
&& !string.IsNullOrEmpty(response.Data?.ReRoute?.DownstreamReRoute?.FirstOrDefault()
?.DownstreamScheme);
}, appBuilder => appBuilder.UseOcelot(builderAction, configuration).Wait());
return app;
}
使用#
在 Startup 里
ConfigurationServices
配置 mvc 和 Ocelot
Configure
方法里配置 ocelot 和 mvc
app.UseOcelotWhenRouteMatch((ocelotBuilder, pipelineConfiguration) =>
{
// This is registered to catch any global exceptions that are not handled
// It also sets the Request Id if anything is set globally
ocelotBuilder.UseExceptionHandlerMiddleware();
// This is registered first so it can catch any errors and issue an appropriate response
ocelotBuilder.UseResponderMiddleware();
ocelotBuilder.UseDownstreamRouteFinderMiddleware();
ocelotBuilder.UseDownstreamRequestInitialiser();
ocelotBuilder.UseRequestIdMiddleware();
ocelotBuilder.UseMiddleware<ClaimsToHeadersMiddleware>();
ocelotBuilder.UseLoadBalancingMiddleware();
ocelotBuilder.UseDownstreamUrlCreatorMiddleware();
ocelotBuilder.UseOutputCacheMiddleware();
ocelotBuilder.UseMiddleware<HttpRequesterMiddleware>();
// cors headers
ocelotBuilder.UseMiddleware<CorsMiddleware>();
});
app.UseMvc();
新建一个 TestController
[Route("/api/[controller]")]
public class TestController : ControllerBase
{
public IActionResult Get()
{
return Ok(new
{
Tick = DateTime.UtcNow.Ticks,
Msg = "Hello Ocelot",
});
}
}
具体代码可以参考这个 网关示例项目
示例项目的 Ocelot 配置是存在 Redis 里面的,配置的 ReRoutes 如下:
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api.php?key=free&appid=0&msg={everything}",
"UpstreamPathTemplate": "/api/chat/{everything}",
"UpstreamHttpMethod": [
"Get",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS"
],
"AddHeadersToRequest": {
},
"RequestIdKey": "RequestId",
"ReRouteIsCaseSensitive": false,
"ServiceName": "",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "api.qingyunke.com",
"Port": 80
}
],
"DangerousAcceptAnyServerCertificateValidator": false
}
],
"GlobalConfiguration": {
"HttpHandlerOptions": {
"AllowAutoRedirect": false,
"UseCookieContainer": false,
"UseTracing": false
}
}
}
运行项目进行测试:
访问 Ocelot 定义的路由 http://localhost:65125/api/chat/hello ,返回信息如图所示:
访问 Mvc 定义的路由 http://localhost:65125/api/test,返回信息如图所示:
上面正常的返回就表示我们的 Ocelot 和 Mvc 同时工作了~
Reference#
作者:weihanli
出处:https://www.cnblogs.com/weihanli/p/integrate-ocelot-route-with-aspnetcore.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
2015-05-22 Get a developer license for windows store app