网站子页怎么做 视频,西安网站建设专业公司,企业管理系统的构成状况,铜陵市建设局网站引言客户端与微服务的通信问题永远是一个绕不开的问题#xff0c;对于小型微服务应用#xff0c;客户端与微服务可以使用直连的方式进行通信#xff0c;但对于对于大型的微服务应用我们将不得不面对以下问题#xff1a;如何降低客户端到后台的请求数量#xff0c;并减少与… 引言客户端与微服务的通信问题永远是一个绕不开的问题对于小型微服务应用客户端与微服务可以使用直连的方式进行通信但对于对于大型的微服务应用我们将不得不面对以下问题如何降低客户端到后台的请求数量并减少与多个微服务的无效交互如何处理微服务间的交叉问题比如授权、数据转换和动态请求派发客户端如何与使用非互联网友好协议的服务进行交互如何打造移动端友好的服务而解决这一问题的方法之一就是借助API网关其允许我们按需组合某些微服务以提供单一入口。接下来本文就来梳理一下eShopOnContainers是如何集成Ocelot网关来进行通信的。Hello Ocelot关于Ocelot张队在Github上贴心的整理了awesome-ocelot系列以便于我们学习。这里就简单介绍下Ocelot不过多展开。 Ocelot是一个开源的轻量级的基于ASP.NET Core构建的快速且可扩展的API网关核心功能包括路由、请求聚合、限速和负载均衡集成了IdentityServer4以提供身份认证和授权基于Consul提供了服务发现能力借助Polly实现了服务熔断能够很好的和k8s和Service Fabric集成。Ocelot 集成eShopOnContainers中的以下六个微服务都是通过网关API进行发布的。引入网关层后eShopOnContainers的整体架构如下图所示从代码结构来看其基于业务边界Marketing和Shopping分别为Mobile和Web端建立多个网关项目这样做利于隔离变化降低耦合且保证开发团队的独立自主性。所以我们在设计网关时也应注意到这一点切忌设计大一统的单一API网关以避免整个微服务架构体系的过度耦合。在网关设计中应当根据业务和领域去决定API网关的边界尽量设计细粒度而非粗粒度的API网关。eShopOnContainers中 ApiGateways文件下是相关的网关项目。相关项目结构如下图所示。从代码结构看有四个 configuration.json文件该文件就是ocelot的配置文件其中主要包含两个节点{ ReRoutes: [], GlobalConfiguration: {}}那4个独立的配置文件是怎样设计成4个独立的API网关的呢 在eShopOnContainers中首先基于 OcelotApiGw项目构建单个Ocelot API网关Docker容器镜像然后在运行时通过使用 docker volume分别挂载不同路径下的 configuration.json文件来启动不同类型的API-Gateway容器。示意图如下docker-compse.yml中相关配置如下// docker-compse.ymlmobileshoppingapigw: image: eshop/ocelotapigw:${TAG:-latest} build: context: . dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile// docker-compse.override.ymlmobileshoppingapigw: environment: - ASPNETCORE_ENVIRONMENTDevelopment - IdentityUrlhttp://identity.api ports: - 5200:80 volumes: - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration通过这种方式将API网关分成多个API网关不仅可以同时重复使用相同的Ocelot Docker镜像而且开发团队可以专注于团队所属微服务的开发并通过独立的Ocelot配置文件来管理自己的API网关。而关于Ocelot的代码集成主要就是指定配置文件以及注册Ocelot中间件。核心代码如下publicvoidConfigureServices(IServiceCollection services){ //.. services.AddOcelot(newConfigurationBuilder().AddJsonFile(Path.Combine(configuration,configuration.json)).Build());}publicvoidConfigure(IApplicationBuilder app,IHostingEnvironment env){ //... app.UseOcelot().Wait();}请求聚合在单体应用中时进行页面展示时可以一次性关联查询所需的对象并返回但是对于微服务应用来说某一个页面的展示可能需要涉及多个微服务的数据那如何进行将多个微服务的数据进行聚合呢首先不可否认的是Ocelot提供了请求聚合功能但是就其灵活性而言远不能满足我们的需求。因此一般会选择自定义聚合器来完成灵活的聚合功能。在eShopOnContainers中就是通过独立ASP.NET Core Web API项目来提供明确的聚合服务。 Mobile.Shopping.HttpAggregator和 Web.Shopping.HttpAggregator即是用于提供自定义的请求聚合服务。下面就以 Web.Shopping.HttpAggregator项目为例来讲解自定义聚合的实现思路。 首先该网关项目是基于ASP.NET Web API构建。其代码结构如下图所示其核心思路是自定义网关服务借助HttpClient发起请求。我们来看一下 BasketService的实现代码public class BasketService : IBasketService{ private readonly HttpClient _apiClient; private readonly ILoggerBasketService _logger; private readonly UrlsConfig _urls; public BasketService(HttpClient httpClient,ILoggerBasketService logger, IOptionsUrlsConfig config) { _apiClient httpClient; _logger logger; _urls config.Value; } public async TaskBasketData GetById(string id) { var data await _apiClient.GetStringAsync(_urls.Basket UrlsConfig.BasketOperations.GetItemById(id)); var basket !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObjectBasketData(data) : null; return basket; }}代码中主要是通过构造函数注入 HttpClient然后方法中借助 HttpClient实例发起相应请求。那 HttpClient实例是如何注册的呢我们来看下启动类里服务注册逻辑。public static IServiceCollection AddApplicationServices(this IServiceCollection services){ //register delegating handlers services.AddTransientHttpClientAuthorizationDelegatingHandler(); services.AddSingletonIHttpContextAccessor, HttpContextAccessor(); //register http services services.AddHttpClientIBasketService, BasketService() .AddHttpMessageHandlerHttpClientAuthorizationDelegatingHandler() .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy()); services.AddHttpClientICatalogService, CatalogService() .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy()); services.AddHttpClientIOrderApiClient, OrderApiClient() .AddHttpMessageHandlerHttpClientAuthorizationDelegatingHandler() .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy()); return services;}从代码中可以看到主要做了三件事注册 HttpClientAuthorizationDelegatingHandler负责为HttpClient构造 Authorization请求头注册 IHttpContextAccessor用于获取 HttpContext为三个网关服务分别注册独立的 HttpClient其中 IBasketServie和 IOrderApiClient需要认证所以注册了 HttpClientAuthorizationDelegatingHandler用于构造 Authorization请求头。另外分别注册了 Polly的请求重试和断路器策略。那 HttpClientAuthorizationDelegatingHandler是如何构造 Authorization请求头的呢直接看代码实现public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler{ private readonly IHttpContextAccessor _httpContextAccesor; public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor) { _httpContextAccesor httpContextAccesor; } protected override async TaskHttpResponseMessage SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var authorizationHeader _httpContextAccesor.HttpContext .Request.Headers[Authorization]; if (!string.IsNullOrEmpty(authorizationHeader)) { request.Headers.Add(Authorization, new Liststring() { authorizationHeader }); } var token await GetToken(); if (token ! null) { request.Headers.Authorization new AuthenticationHeaderValue(Bearer, token); } return await base.SendAsync(request, cancellationToken); } async Taskstring GetToken() { const string ACCESS_TOKEN access_token; return await _httpContextAccesor.HttpContext .GetTokenAsync(ACCESS_TOKEN); }}代码实现也很简单首先从 _httpContextAccesor.HttpContext.Request.Headers[Authorization]中取若没有则从 _httpContextAccesor.HttpContext.GetTokenAsync(access_token)中取拿到访问令牌后添加到请求头 request.Headers.AuthorizationnewAuthenticationHeaderValue(Bearer,token);即可。这里你肯定有个疑问就是为什么不是到Identity microservices去取访问令牌而是直接从 _httpContextAccesor.HttpContext.GetTokenAsync(access_token)中取访问令牌Good Question因为对于网关项目而言其本身也是需要认证的在访问网关暴露的需要认证的API时其已经同Identity microservices协商并获取到令牌并将令牌内置到 HttpContext中了。所以对于同一个请求上下文我们仅需将网关项目申请到的令牌传递下去即可。Ocelot网关中如何集成认证和授权不管是独立的微服务还是网关认证和授权问题都是要考虑的。Ocelot允许我们直接在网关内的进行身份验证如下图所示因为认证授权作为微服务的交叉问题所以将认证授权作为横切关注点设计为独立的微服务更符合关注点分离的思想。而Ocelot网关仅需简单的配置即可完成与外部认证授权服务的集成。1. 配置认证选项首先在 configuration.json配置文件中为需要进行身份验证保护API的网关设置 AuthenticationProviderKey。比如{ DownstreamPathTemplate: /api/{version}/{everything}, DownstreamScheme: http, DownstreamHostAndPorts: [ { Host: basket.api, Port: 80 } ], UpstreamPathTemplate: /api/{version}/b/{everything}, UpstreamHttpMethod: [], AuthenticationOptions: { AuthenticationProviderKey: IdentityApiKey, AllowedScopes: [] }}2. 注册认证服务当Ocelot运行时它将根据Re-Routes节点中定义的 AuthenticationOptions.AuthenticationProviderKey去确认系统是否注册了相对应身份验证提供程序。如果没有那么Ocelot将无法启动。如果有则ReRoute将在执行时使用该提供程序。 在 OcelotApiGw的启动配置中就注册了 AuthenticationProviderKeyIdentityApiKey的认证服务。public void ConfigureServices (IServiceCollection services) { var identityUrl _cfg.GetValuestring (IdentityUrl); var authenticationProviderKey IdentityApiKey; //… services.AddAuthentication () .AddJwtBearer (authenticationProviderKey, x { x.Authority identityUrl; x.RequireHttpsMetadata false; x.TokenValidationParameters new Microsoft.IdentityModel.Tokens.TokenValidationParameters () { ValidAudiences new [] { orders, basket, locations, marketing, mobileshoppingagg, webshoppingagg } }; }); //...}这里需要说明一点的是 ValidAudiences用来指定可被允许访问的服务。其与各个微服务启动类中 ConfigureServices()内 AddJwtBearer()指定的 Audience相对应。比如// prevent from mapping sub claim to nameidentifier.JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear ();var identityUrl Configuration.GetValuestring (IdentityUrl);services.AddAuthentication (options { options.DefaultAuthenticateScheme JwtBearerDefaults.AuthenticationScheme options.DefaultChallengeScheme JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer (options { options.Authority identityUrl; options.RequireHttpsMetadata false; options.Audience basket;});3. 按需配置申明进行鉴权另外有一点不得不提的是Ocelot支持在身份认证后进行基于声明的授权。仅需在 ReRoute节点下配置 RouteClaimsRequirement即可RouteClaimsRequirement: { UserType: employee}在该示例中当调用授权中间件时Ocelot将查找用户是否在令牌中是否存在 UserType:employee的申明。如果不存在则用户将不被授权并响应403。最后经过以上的讲解想必你对eShopOnContainers中如何借助API 网关模式解决客户端与微服务的通信问题有所了解但其就是万金油吗API 网关模式也有其缺点所在。网关层与内部微服务间的高度耦合。网关层可能出现单点故障。API网关可能导致性能瓶颈。API网关如果包含复杂的自定义逻辑和数据聚合额外增加了团队的开发维护沟通成本。虽然IT没有银弹但eShopOnContainers中网关模式的应用案例至少指明了一种解决问题的思路。而至于在实战场景中的技术选型适合的就是最好的。原文地址http://www.cnblogs.com/sheng-jie/p/10476436.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com