澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站:polly微服务故障管理库,

2019-07-15 作者:www.8455.com   |   浏览(104)

介绍:

基本介绍:

安装:

下载地址:

运行:

consul agent -dev

澳门新萄京官方网站 1

显示这个界面说明已经开启成功。

页面显示:

然后访问8500端口就可以看到页面:

澳门新萄京官方网站 2

命令:

consul members:输出当前服务的信息,显示的所有配置节点。

install-package Consul:在vs项目中安装Consul

熔断、降级:

引言

客户端与微服务的通信问题永远是一个绕不开的问题,对于小型微服务应用,客户端与微服务可以使用直连的方式进行通信,但对于对于大型的微服务应用我们将不得不面对以下问题:

  1. 如何降低客户端到后台的请求数量,并减少与多个微服务的无效交互?
  2. 如何处理微服务间的交叉问题,比如授权、数据转换和动态请求派发?
  3. 客户端如何与使用非互联网友好协议的服务进行交互?
  4. 如何打造移动端友好的服务?

而解决这一问题的方法之一就是借助API网关,其允许我们按需组合某些微服务以提供单一入口。

接下来,本文就来梳理一下eShopOnContainers是如何集成Ocelot网关来进行通信的。

澳门新萄京官方网站 3

客户端与微服务的通信问题永远是一个绕不开的问题,对于小型微服务应用,客户端与微服务可以使用直连的方式进行通信,但对于对于大型的微服务应用我们将不得不面对以下问题:

Ocelot是一个.NET API网关。该项目针对的是使用.NET运行微服务/面向服务架构的人员,他们需要一个统一的入口进入他们的系统。然而,它可以处理任何说HTTP并在ASP.NET Core支持的任何平台上运行的任何东西。

服务连接:

开启consul服务之后需要把现有的项目连接集群到consul服务,这时候需要在项目中注册服务(在startup.cs文件下的Configure方法):

澳门新萄京官方网站 4澳门新萄京官方网站 5

 String ip = Configuration["ip"];//部署到不同服务器的时候不能写成127.0.0.1或者0.0.0.0,因为这是让服务消费者调用的地址            int port = int.Parse(Configuration["port"]);//获取服务端口            var client = new ConsulClient(ConfigurationOverview); //回调获取            var result = client.Agent.ServiceRegister(new AgentServiceRegistration()            {                ID = "ServerNameFirst"   Guid.NewGuid(),//服务编号保证不重复                Name = "MsgServer",//服务的名称                Address = ip,//服务ip地址                Port = port,//服务端口                Check = new AgentServiceCheck //健康检查                {                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后反注册                    Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔(定时检查服务是否健康)                    HTTP = $"http://{ip}:{port}/api/Health",//健康检查地址                    Timeout = TimeSpan.FromSeconds(5)//服务的注册时间                }            });

View Code

之后在增加一个回调方法:

回调方法是代表的consul服务的地址配置。

 private static void ConfigurationOverview(ConsulClientConfiguration obj)        {            //consul的地址            obj.Address = new Uri("http://127.0.0.1:8500");            //数据中心命名            obj.Datacenter = "dc1";        }

服务到这里已经是配置完毕。但是我们怎么注销服务哪。当然是有办法的拉。通过api我们可以知道ServiceDeregister方法是注销服务的方法。那么我们应该怎么写哪:

首先我们要去了解一下IApplicationLifetime接口:允许消费者在优雅关机期间执行清理工作

ApplicationStarted:当应用程序主机已完全启动并将要等待时触发

ApplicationStopping:当应用程序主机执行优美关机时触发。请求可能还在运行中。关闭将阻止此事件完成

ApplicationStopped:当应用程序主机执行关机时触发。所有请求应该在这一点完成。关机将阻止此事件完成。

好了,我的英语确实不好,这些就是自动翻译的意思。不过也能让我们明白大概的意思。知道有这个东西我们就可以实现功能了完整代码:

澳门新萄京官方网站 6澳门新萄京官方网站 7

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)        {            if (env.IsDevelopment            {                app.UseDeveloperExceptionPage();            }            app.UseMvc();            String ip = Configuration["ip"];//部署到不同服务器的时候不能写成127.0.0.1或者0.0.0.0,因为这是让服务消费者调用的地址            int port = int.Parse(Configuration["port"]);//获取服务端口            var client = new ConsulClient(ConfigurationOverview); //回调获取            string serverId = "ServerNameFirst"   Guid.NewGuid();            var result = client.Agent.ServiceRegister(new AgentServiceRegistration()            {                ID = serverId,//服务编号保证不重复                Name = "MsgServer",//服务的名称                Address = ip,//服务ip地址                Port = port,//服务端口                Check = new AgentServiceCheck //健康检查                {                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后反注册                    Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔(定时检查服务是否健康)                    HTTP = $"http://{ip}:{port}/api/Health",//健康检查地址                    Timeout = TimeSpan.FromSeconds(5)//服务的注册时间                }            });            lifetime.ApplicationStopping.Register =>            {                Console.WriteLine("注销方法");                client.Agent.ServiceDeregister.Wait();//服务停止时取消注册            });        }

View Code

运行效果截图:

澳门新萄京官方网站 8

熔断:熔断就是我们常说的“保险丝”,意为当服务出现某些状况时,切断服务,从而防止应用程序不断地常识执行可能会失败的操作造成系统的“雪崩”,或者大量的超时等待导致系统卡死等情况,很多地方也将其成为“过载保护”。

Hello Ocelot

关于Ocelot,张队在Github上贴心的整理了awesome-ocelot系列以便于我们学习。这里就简单介绍下Ocelot,不过多展开。
Ocelot是一个开源的轻量级的基于ASP.NET Core构建的快速且可扩展的API网关,核心功能包括路由、请求聚合、限速和负载均衡,集成了IdentityServer4以提供身份认证和授权,基于Consul提供了服务发现能力,借助Polly实现了服务熔断,能够很好的和k8s和Service Fabric集成。

  1. 如何降低客户端到后台的请求数量,并减少与多个微服务的无效交互?
  2. 如何处理微服务间的交叉问题,比如授权、数据转换和动态请求派发?
  3. 客户端如何与使用非互联网友好协议的服务进行交互?
  4. 如何打造移动端友好的服务?

Ocelot是一组按特定顺序的中间件,Ocelot操纵HttpRequest对象进入由其配置指定的状态,直到它到达请求生成器中间件,在该中间件中创建HttpRequestMessage对象,该对象用于向下游服务发出请求。提出请求的中间件是Ocelot管道中的最后一件事。它不叫下一个中间件。来自下游服务的响应存储在每个请求作用域存储库中,并在请求返回到Ocelot管道时进行恢复。有一件中间件将HttpResponseMessage映射到HttpResponse对象上,并返回给客户端。这基本上是与其他一些功能。

客户端:

简单介绍一个获取服务所有地址,然后打印并从其中随机选取一个进行请求并打印:

澳门新萄京官方网站 9澳门新萄京官方网站 10

       static List<string> Urls = new List<string>();        static void Main(string[] args)        {            Console.WriteLine("开始输出当前所有服务地址");            Catalog_Nodes().GetAwaiter().GetResult();            //Console.WriteLine(HelloConsul().GetAwaiter().GetResult;            Console.WriteLine("开始随机请求一个地址服务地址");            int index = new Random().Next(Urls.Count);            string url = Urls[index];            string param = "";//这里是开始位置            param  = "{";            param  = """   "id"   "":""   5   "",";            param = param.TrimEnd(',');            param  = "}";            Console.WriteLine("请求的随机地址:"   url);            string result = HttpClientHelpClass.PostResponse(url, param, out string statusCode);            Console.WriteLine("返回状态:"   statusCode);            Console.WriteLine("返回结果:"   result);            Console.ReadLine();        }        public static async Task Catalog_Nodes()        {            var client = new ConsulClient();            var nodeList = await client.Agent.Services();            var url = nodeList.Response.Values;            foreach (var item in url)            {                string Address = item.Address;                int port = item.Port;                string name = item.Service;                Console.WriteLine($"地址:{Address}:{port},name:{name}");                Urls.Add($"http://{Address}:{port}/api/Test");            }        }

View Code

降级:降级的目的就是当某个服务提供者发生故障的时候,向调用方返回一个替代响应或者错误响应。

Ocelot 集成

eShopOnContainers中的以下六个微服务都是通过网关API进行发布的。
澳门新萄京官方网站 11

引入网关层后,eShopOnContainers的整体架构如下图所示:
澳门新萄京官方网站 12

从代码结构来看,其基于业务边界(Marketing和Shopping)分别为Mobile和Web端建立多个网关项目,这样做利于隔离变化,降低耦合,且保证开发团队的独立自主性。所以我们在设计网关时也应注意到这一点,切忌设计大一统的单一API网关,以避免整个微服务架构体系的过度耦合。在网关设计中应当根据业务和领域去决定API网关的边界,尽量设计细粒度而非粗粒度的API网关。

eShopOnContainers中ApiGateways文件下是相关的网关项目。相关项目结构如下图所示。

澳门新萄京官方网站 13

从代码结构看,有四个configuration.json文件,该文件就是ocelot的配置文件,其中主要包含两个节点:

{ "ReRoutes": [], "GlobalConfiguration": {}}

那4个独立的配置文件是怎样设计成4个独立的API网关的呢?
在eShopOnContainers中,首先基于OcelotApiGw项目构建单个Ocelot API网关Docker容器镜像,然后在运行时,通过使用docker volume分别挂载不同路径下的configuration.json文件来启动不同类型的API-Gateway容器。示意图如下:
澳门新萄京官方网站 14

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_ENVIRONMENT=Development - IdentityUrl=http://identity.api ports: - "5200:80" volumes: - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration

通过这种方式将API网关分成多个API网关,不仅可以同时重复使用相同的Ocelot Docker镜像,而且开发团队可以专注于团队所属微服务的开发,并通过独立的Ocelot配置文件来管理自己的API网关。

而关于Ocelot的代码集成,主要就是指定配置文件以及注册Ocelot中间件。核心代码如下:

public void ConfigureServices(IServiceCollection services){    //..    services.AddOcelot (new ConfigurationBuilder ()    .AddJsonFile (Path.Combine ("configuration", "configuration.json"))    .Build ;}public void Configure(IApplicationBuilder app, IHostingEnvironment env){     //...    app.UseOcelot;}

而解决这一问题的方法之一就是借助API网关,其允许我们按需组合某些微服务以提供单一入口。

Ocelot只能用于.NET Core,并且目前已经构建到netstandard2.0。所有下面 我们使用.NET Core 2.1做演示。

系列章节:

微服务系列文章主要介绍微服务所使用到的一些技术和一些技术示例:

  • 微服务——微服务的介绍和目录
  • 微服务——服务发现在windows下简单使用
  • 微服务——微服务故障处理库
  • 微服务——动态代理AspectCore的使用
  • 微服务——网关Ocelot Consul实现集群轮询

介绍:

POLLY是一个.NET回弹和瞬态故障处理库,它允许开发人员以流畅和线程安全的方式表达诸如重试、断路器、超时、隔板隔离和回退等策略。github官方解释嘿嘿。

Polly以.NET Standard 1.1(覆盖范围:.NET Framework 4.5-4.6.1,.NET Core 1.0,Mono,Xamarin,UWP,WP8.1 )

            .NET Standard 2.0 (覆盖范围:.NET Framework 4.6.1, .NET Core 2.0 以及后来的Mono,Xamarin和UWP目标)

请求聚合

在单体应用中时,进行页面展示时,可以一次性关联查询所需的对象并返回,但是对于微服务应用来说,某一个页面的展示可能需要涉及多个微服务的数据,那如何进行将多个微服务的数据进行聚合呢?首先,不可否认的是,Ocelot提供了请求聚合功能,但是就其灵活性而言,远不能满足我们的需求。因此,一般会选择自定义聚合器来完成灵活的聚合功能。在eShopOnContainers中就是通过独立ASP.NET Core Web API项目来提供明确的聚合服务。Mobile.Shopping.HttpAggregatorWeb.Shopping.HttpAggregator即是用于提供自定义的请求聚合服务。

澳门新萄京官方网站 15

下面就以Web.Shopping.HttpAggregator项目为例来讲解自定义聚合的实现思路。
首先,该网关项目是基于ASP.NET Web API构建。其代码结构如下图所示:
澳门新萄京官方网站 16

其核心思路是自定义网关服务借助HttpClient发起请求。我们来看一下BasketService的实现代码:

public class BasketService : IBasketService{    private readonly HttpClient _apiClient;    private readonly ILogger<BasketService> _logger;    private readonly UrlsConfig _urls;    public BasketService(HttpClient httpClient,ILogger<BasketService> logger, IOptions<UrlsConfig> config)    {        _apiClient = httpClient;        _logger = logger;        _urls = config.Value;    }    public async Task<BasketData> GetById(string id)    {        var data = await _apiClient.GetStringAsync(_urls.Basket    UrlsConfig.BasketOperations.GetItemById;        var basket = !string.IsNullOrEmpty ? JsonConvert.DeserializeObject<BasketData> : null;        return basket;    }}

代码中主要是通过构造函数注入HttpClient,然后方法中借助HttpClient实例发起相应请求。那HttpClient实例是如何注册的呢,我们来看下启动类里服务注册逻辑。

public static IServiceCollection AddApplicationServices(this IServiceCollection services){    //register delegating handlers    services.AddTransient<HttpClientAuthorizationDelegatingHandler>();    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();    //register http services      services.AddHttpClient<IBasketService, BasketService>()        .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()        .AddPolicyHandler(GetRetryPolicy        .AddPolicyHandler(GetCircuitBreakerPolicy;    services.AddHttpClient<ICatalogService, CatalogService>()        .AddPolicyHandler(GetRetryPolicy        .AddPolicyHandler(GetCircuitBreakerPolicy;    services.AddHttpClient<IOrderApiClient, OrderApiClient>()        .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()        .AddPolicyHandler(GetRetryPolicy        .AddPolicyHandler(GetCircuitBreakerPolicy;    return services;}

从代码中可以看到主要做了三件事:

  1. 注册HttpClientAuthorizationDelegatingHandler负责为HttpClient构造Authorization请求头
  2. 注册IHttpContextAccessor用于获取HttpContext
  3. 为三个网关服务分别注册独立的HttpClient,其中IBasketServieIOrderApiClient需要认证,所以注册了HttpClientAuthorizationDelegatingHandler用于构造Authorization请求头。另外,分别注册了Polly的请求重试和断路器策略。

HttpClientAuthorizationDelegatingHandler是如何构造Authorization请求头的呢?直接看代码实现:

public class HttpClientAuthorizationDelegatingHandler     : DelegatingHandler{    private readonly IHttpContextAccessor _httpContextAccesor;    public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)    {        _httpContextAccesor = httpContextAccesor;    }    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)    {        var authorizationHeader = _httpContextAccesor.HttpContext            .Request.Headers["Authorization"];        if (!string.IsNullOrEmpty(authorizationHeader))        {            request.Headers.Add("Authorization", new List<string>() { authorizationHeader });        }        var token = await GetToken();        if (token != null)        {            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);        }        return await base.SendAsync(request, cancellationToken);    }    async Task<string> 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.Authorization = new AuthenticationHeaderValue("Bearer", token);即可。

这里你肯定有个疑问就是:为什么不是到Identity microservices去取访问令牌,而是直接从_httpContextAccesor.HttpContext.GetTokenAsync("access_token")中取访问令牌?

Good Question,因为对于网关项目而言,其本身也是需要认证的,在访问网关暴露的需要认证的API时,其已经同Identity microservices协商并获取到令牌,并将令牌内置到HttpContext中了。所以,对于同一个请求上下文,我们仅需将网关项目申请到的令牌传递下去即可。

接下来,本文就来梳理一下eShopOnContainers是如何集成Ocelot网关来进行通信的。

创建一个基本示例:

首先我们创建一个.NET Core 2.1空项目。

当然我们还是要先引用的拉, Nuget 命令行: Install-Package Ocelot

配置:添加一个json文件实现最基本的配置:

{
    "ReRoutes": [],
    "GlobalConfiguration": {
        "BaseUrl": "urladdress"
    }
}

这里最重要的是BaseUrl。Ocelot需要知道它正在运行的URL,以便执行标题查找和替换以及某些管理配置。当设置这个URL时,它应该是客户端将看到的Ocelot运行的外部URL。

然后我们将刚才的配置文件加入到ASP.NET Core Configuration:Program.cs

澳门新萄京官方网站 17澳门新萄京官方网站 18

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                   .ConfigureAppConfiguration((hostingContext, builder) =>
                   {
                       builder
                       .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
                       .AddJsonFile("ocelot.json");
                   })
                .UseStartup<Startup>();

View Code

最后在添加服务以及设置中间件:Startup.cs

澳门新萄京官方网站 19澳门新萄京官方网站 20

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddOcelot();//添加ocelot服务
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseOcelot().Wait();//设置所有的Ocelot中间件
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }
    }

View Code

 这些就是基本的所需编程代码。

安装:

首先当然是创建一个控制台项目,然后通过NuGet安装:

Install-Package Polly

澳门新萄京官方网站 21

出现以上界面就说明你已经安装了最新的版本到你的项目;

Ocelot网关中如何集成认证和授权

不管是独立的微服务还是网关,认证和授权问题都是要考虑的。Ocelot允许我们直接在网关内的进行身份验证,如下图所示:
澳门新萄京官方网站 22

因为认证授权作为微服务的交叉问题,所以将认证授权作为横切关注点设计为独立的微服务更符合关注点分离的思想。而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的启动配置中,就注册了AuthenticationProviderKey:IdentityApiKey的认证服务。

public void ConfigureServices (IServiceCollection services) {    var identityUrl = _cfg.GetValue<string> ("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.GetValue<string> ("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。

澳门新萄京官方网站 23使用自定义的API 网关服务

配置文件的详细分析:

Ocelot的主要功能是收取HTTP请求并将它们转发到下游服务。目前以另一个http请求的形式出现。Ocelot描述了将一个请求作为ReRoute路由到另一个请求。为了在Ocelot中获得任何工作,您需要在配置中设置ReRoute。

说道这里我们补充一下刚才写的json文件的两个根节点:ReRoutes和GlobalConfiguration。

    ReRoutes:是一个数组,其中的每一个元素代表了一个路由,我们可以针对每一个路由进行以上功能配置,告诉Ocelot如何处理上游请求的对象。

    GlobalConfiguration:全局配置,可以适当的节约配置,比如baseurl节点,服务发现配置。

这样我们就实现了通过配置文件可以完成对Ocelot的功能配置:路由、服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、Header头传递等。

配置一个示例:下面这个配置信息就是将用户的请求 /ProductService/1 转发到 localhost:8001/api/Test/1

澳门新萄京官方网站 24澳门新萄京官方网站 25

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/Test/{postId}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "127.0.0.1",
          "Port": 8001
        }
      ],
      "UpstreamPathTemplate": "/ProductService/{postId}",
      "UpstreamHttpMethod": [ "Get", "Delete" ]
    }
  ],
  "GlobalConfiguration": {
   // "BaseUrl": "http://127.0.0.1:8887/"
  }
}

View Code

  • DownstreamPathTemplate:下游方位url路径
  • DownstreamScheme:下游服务http schema
  • DownstreamHostAndPorts:下游服务的地址,如果使用LoadBalancer的话这里可以填多项
  • UpstreamPathTemplate: 上游也就是用户输入的请求Url模板
  • UpstreamHttpMethod: 上游请求http方法,可使用数组:Get ,Delete等

好了这样就实现了一个基本的Ocelot网关的转发示例。

下面让我们来看一下效果吧:

首先我们运行起来webapi项目发布在8001端口。然后访问地址是:

我们看到的结果是:

澳门新萄京官方网站 26

然后我们启动我们的网关服务;发布在端口8888下,根据以上配置我们可以看到方位地址为:

然后同样的请求结果是:

澳门新萄京官方网站 27

这样我们就实现使用统一网关来访问不同的地址,以便我们以后实现微服务的分发部署,虽然是不是多个接口,但是我们给上游访问还是提供一个接口,我们内部实现访问该访问那个接口。

至于具体怎发布也可参考这篇文章:

策略介绍:

polly通过官方介绍我们可以知道有7种恢复策略,先不管会不会,先列出来再说哈哈:

    重试策略(Retry):许多故障是短暂的,并且在短暂的延迟后可能会自我纠正。允许我们做的是能够自动配置重试机制

    断路器(Circuit-breaker):当一个系统严重挣扎时,快速失败优于让用户/呼叫者等待。 说白了就是应该优先直接返回失败,而不是一直让用户等待。保护故障系统免受过载可以帮助恢复。

    超时(Timeout):超时策略针对的前置条件是超过一定的等待时间,想要得到成功的结果是不可能的,保证调用者不必等待超时。

 

    隔板隔离(Bulkhead Isolation):隔板隔离针对的前置条件是当进程出现故障时,多个失败一直在主机中对资源(例如线程/ CPU)一直占用。下游系统故障也可能导致上游失败。这两个风险都将造成严重的后果。都说一粒老鼠子屎搅浑一锅粥,而Polly则将受管制的操作限制在固定的资源池中,免其他资源受其影响。

 

    缓存(Cache):就是一些请求,会把数据缓存起来,然后在持续一段时间内,直接从缓存中取。

 

    回退(Fallback):操作仍然会失败,也就是说当发生这样的事情时我们打算做什么。也就是说定义失败返回操作。我们在使用时就是所说的降级。

 

    策略包装(PolicyWrap):不同的故障需要不同的策略 弹性意味着使用组合。

最后

经过以上的讲解,想必你对eShopOnContainers中如何借助API 网关模式解决客户端与微服务的通信问题有所了解,但其就是万金油吗?API 网关模式也有其缺点所在。

  1. 网关层与内部微服务间的高度耦合。
  2. 网关层可能出现单点故障。
  3. API网关可能导致性能瓶颈。
  4. API网关如果包含复杂的自定义逻辑和数据聚合,额外增加了团队的开发维护沟通成本。

虽然IT没有银弹,但eShopOnContainers中网关模式的应用案例至少指明了一种解决问题的思路。而至于在实战场景中的技术选型,适合的就是最好的。

关于Ocelot,张队在Github上贴心的整理了awesome-ocelot系列以便于我们学习。这里就简单介绍下Ocelot,不过多展开。Ocelot是一个开源的轻量级的基于ASP.NET Core构建的快速且可扩展的API网关,核心功能包括路由、请求聚合、限速和负载均衡,集成了IdentityServer4以提供身份认证和授权,基于Consul提供了服务发现能力,借助Polly实现了服务熔断,能够很好的和k8s和Service Fabric集成。

路由小知识:

UpstreamHost=>"UpstreamHost": "baidu.com":上游主机

    此功能允许您基于上游主机进行ReRoutes。这通过查看客户端使用的主机头来工作,然后将其用作我们用来识别ReRoute的信息的一部分。这样就是显示了只有在主机头值为baidu.com时才会匹配。

Priority=> "Priority": 0:优先级

    此功能设置访问路由的优先级,假设在同一个路由下有多个路由,会根据优先级匹配优先级最高的,0是最低的。

Dynamic Routing:动态路由

    这个主要是为了服务发现而实现的,在这种模式下,Ocelot将使用上游路径的第一个分段来查找服务发现提供商的下游服务。官网给出的大概配置效果:

澳门新萄京官方网站 28澳门新萄京官方网站 29

{
    "ReRoutes": [],
    "Aggregates": [],
    "GlobalConfiguration": {
        "RequestIdKey": null,
        "ServiceDiscoveryProvider": {
            "Host": "localhost",
            "Port": 8510,
            "Type": null,
            "Token": null,
            "ConfigurationKey": null
        },
        "RateLimitOptions": {
            "ClientIdHeader": "ClientId",
            "QuotaExceededMessage": null,
            "RateLimitCounterPrefix": "ocelot",
            "DisableRateLimitHeaders": false,
            "HttpStatusCode": 429
        },
        "QoSOptions": {
            "ExceptionsAllowedBeforeBreaking": 0,
            "DurationOfBreak": 0,
            "TimeoutValue": 0
        },
        "BaseUrl": null,
            "LoadBalancerOptions": {
            "Type": "LeastConnection",
            "Key": null,
            "Expiry": 0
        },
        "DownstreamScheme": "http",
        "HttpHandlerOptions": {
            "AllowAutoRedirect": false,
            "UseCookieContainer": false,
            "UseTracing": false
        }
    }
}

View Code

使用步骤:

polly一般分为三步进行:

  • 定义条件: 定义你要处理的 错误异常/返回结果

  • 定义处理方式 : 重试,熔断,回退

  • 执行

定义条件:    

.Handle<ExceptionType>():限定条件的单个异常Policy;

.Handle<ExceptionType>(ex => ex.Number == 10):具有条件的单个异常类型。

.Handle<HttpRequestException>()
.Or<OperationCanceledException>():多个异常类型,当然他也可以变成具有条件的多个异常类型,类似于单个操作。

定义返回结果的条件:

.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound):用条件处理返回值,处理单个返回值。

.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
.OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.BadGateway):处理多个返回值。

 指定策略(重试):

.Retry():重试一次。

.Retry(3):重试三次,修改数值即可定义自己想使用的次数。

.Retry(3, (exception, retryCount) =>
    {
        // do something 
    }):重试多次,在每次重试都执行一个操作,参数为:当前异常和重试计数。

.Retry(3, (exception, retryCount, context) =>
    {
        // do something 
    }):重试多次,在每次重试都执行一个操作,参数为:当前异常,重试计数和上下文

.RetryForever():永远重试直到成功,同时也也有重试的相同扩展,可以写参数。

.WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
  }):等待并重试,就是在每个重试的时候需要等待指定的执行时间,同样有相同扩展,可以在每个重试调用一个操作。

.WaitAndRetryForever(retryAttempt => 
 TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
    ):等待和重试永远(直到成功)

  指定策略(熔断):

.CircuitBreaker(2, TimeSpan.FromMinutes(1)):在指定数量的连续异常之后中断开。这里就不做过多解释了。

 指定策略(降级):回退

.Fallback<UserAvatar>(UserAvatar.Blank):如果执行错误,则提供替代值,就是出现错误,定义一个返回值给他

.Fallback<UserAvatar>(() => UserAvatar.GetRandomAvatar()) :定义一个方法给他,该方法代替提供值。

执行: 

.Execute(() => DoSomething()):执行一项方法

执行通过任意上下文数据的操作:

var policy = Policy
    .Handle<SomeExceptionType>()
    .Retry(3, (exception, retryCount, context) =>
    {
        var methodThatRaisedException = context["methodName"];
        Log(exception, methodThatRaisedException);
    });

policy.Execute(
    () => DoSomething(),
    new Dictionary<string, object>() {{ "methodName", "some method" }}
);

eShopOnContainers中的以下六个微服务都是通过网关API进行发布的。

Ocelot实现多个端口的轮询:

以上实现的这个有什么用啊,单独发布了接口,然后使用另外一个接口去复制他吗?别急,这只是其中的一个基本使用,现在我们有了基本步骤,我们改一改,实现webapi发布两个接口,8001,8002.然后还使用网关地址访问,可以循环的访问到8001端口和8002端口。

说起来简单,做起来也简单,我们只需要在我们上面的配置上修改一下即可:

澳门新萄京官方网站 30澳门新萄京官方网站 31

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/Test/{postId}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "127.0.0.1",
          "Port": 8001
        },
        {
          "Host": "127.0.0.1",
          "Port": 8002
        }
      ],
      "UpstreamPathTemplate": "/ProductService/{postId}",
      "UpstreamHttpMethod": [ "Get" ],
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      }
    }
  ],
  "GlobalConfiguration": {
    // "BaseUrl": "http://127.0.0.1:8887/"
  }
}

View Code

启动两个端口:

澳门新萄京官方网站 32

重复请求网关两次结果:

澳门新萄京官方网站 33

 使用示例:

降级的使用代码:

澳门新萄京官方网站 34澳门新萄京官方网站 35

 #region 降级
        public static void Downgrade()
        {
            //降级处理程序
            ISyncPolicy policy = Policy.Handle<ArgumentException>()
            .Fallback(() =>
            {
                Console.WriteLine("降级给的返回值结果");
            });
            //运行程序
            policy.Execute(() =>
            {
                Console.WriteLine("任务开始");

                throw new ArgumentException("降级任务出错,马上要降级了");

                Console.WriteLine("任务结束");
            });
        }
        #endregion

View Code

运行结果:

澳门新萄京官方网站 36

重试机制的代码:

出错后重复3次。

澳门新萄京官方网站 37澳门新萄京官方网站 38

 #region 重试机制
        public static void Retry()
        {
            //配置重试次数
            ISyncPolicy policy = Policy.Handle<Exception>().Retry(3);

            try
            {
                policy.Execute(() =>
                {
                    Console.WriteLine("任务开始");
                    if (DateTime.Now.Second % 10 != 0)
                    {
                        throw new Exception("任务出错了,开始重试");
                    }
                    Console.WriteLine("任务结束");
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine("异常结果 : "   ex.Message);
            }
        }
        #endregion

View Code

运行结果:

澳门新萄京官方网站 39

 熔断机制代码:

但出现错误连续三次后,等待20秒后进行

澳门新萄京官方网站 40澳门新萄京官方网站 41

 #region 熔断机制
        public static void Fusing()
        {

            Action<Exception, TimeSpan> onBreak = (exception, timespan) =>
            {
                Console.WriteLine("1");
            };
            Action onReset = () =>
            {
                Console.WriteLine("2");
            };
            ISyncPolicy policy = Policy.Handle<Exception>().CircuitBreaker(3, TimeSpan.FromSeconds(20), onBreak, onReset);
            while (true)
            {
                try
                {

                    policy.Execute(() =>
                        {
                            Console.WriteLine("任务开始");

                            throw new Exception("出错了");

                            Console.WriteLine("任务结束");
                        });

                }
                catch (Exception ex)
                {
                    Console.WriteLine("---------------异常结果-------------- : "   ex.Message   "时间:"   DateTime.Now);
                }
                System.Threading.Thread.Sleep(5000);
            }
        }
        #endregion

View Code

运行结果:

澳门新萄京官方网站 42

混合示例(重试 降级)代码:

出错重试三次后第四次进行降级处理:主要是warp方法来实现的,特别说明warp方法是:最外面(在左边)到最里面(右边)的策略。也就是说从右向左执行方法;

澳门新萄京官方网站 43澳门新萄京官方网站 44

 #region 重试 降级
        public static void RetryDowngrade()
        {
            try
            {
                //降级处理程序
                ISyncPolicy policy = Policy.Handle<Exception>()
                .Fallback(() =>
                {
                    Console.WriteLine("降级成功");
                });
                //配置重试次数
                ISyncPolicy policy2 = Policy.Handle<Exception>().Retry(3, (exception, retryCount, context) =>
                             {
                                 Console.WriteLine(retryCount);

                             });
                //合并
                ISyncPolicy mainPolicy = Policy.Wrap(policy, policy2);
                mainPolicy.Execute(() =>
                {
                    Console.WriteLine("任务开始");

                    throw new Exception("出错了");

                    Console.WriteLine("任务结束");
                });
            }
            catch (Exception ex)
            {

                Console.WriteLine("异常结果 : "   ex.Message);
            }
        }
        #endregion

View Code

运行结果:

澳门新萄京官方网站 45

 源码下载:PollyConsole.rar

澳门新萄京官方网站 46

Ocelot Consul:

实现目标:启动服务发现然后模拟集群发布功能,实现发布端口8001,8002后,启动服务发现,然后配置Ocelot网关。实现访问统一接口可以轮询访问8001,8002,8001,8002,...这样。然后可以在添加8003,继续规则。

实现以上目标我们不需要该我们的示例代码,只需要修改配置json文件即可:

澳门新萄京官方网站 47澳门新萄京官方网站 48

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/Test/{postId}",
      "DownstreamScheme": "http",
      "UpstreamPathTemplate": "/Product123Service/{postId}",
      "UpstreamHttpMethod": [ "Get" ],
      "ServiceName": "ProductService",
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      "UseServiceDiscovery": true
    }
  ],
  "GlobalConfiguration": {
    // "BaseUrl": "http://127.0.0.1:8887/"
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "PollConsul",
      "PollingInterval": 100
    }
  }
}

View Code

这个就是我们的服务功能:

Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口。目前,这仅在GlobalConfiguration部分中受支持,这意味着将为所有的ReRoute使用相同的服务发现提供程序,以便在ReRoute级别指定ServiceName。

  • ServiceName:consul的服务名称
  • LoadBalancerOptions:使用的算法,目前有两种RoundRobin(轮询方式)和LeastConnection(最小连接)
  • UseServiceDiscovery:是否启用服务发现功能 true:为启动
  • ServiceDiscoveryProvider:配置服务发现的一些配置
  • Host:主机地址
  • Port:端口
  • PollingInterval:轮询的间隔时间,以毫秒为单位。并告诉Ocelot多久可以向Consul调用服务配置的更改

想要了解更多可以访问Ocelot官网:

系列目录

微服务系列文章主要介绍微服务所使用到的一些技术和一些技术示例:

  • 微服务——微服务的介绍和目录
  • 微服务——【Consul】服务发现在windows下简单使用(一)
  • 微服务——【polly】微服务故障处理库(二)
  • 微服务——动态代理AspectCore的使用(三) 
  • 微服务——网关Ocelot Consul实现集群轮询(四)

引入网关层后,eShopOnContainers的整体架构如下图所示:

系列目录:

微服务系列文章主要介绍微服务所使用到的一些技术和一些技术示例:

  • 微服务——微服务的介绍和目录
  • 微服务——【Consul】服务发现在windows下简单使用(一)
  • 微服务——【polly】微服务故障处理库(二)
  • 微服务——动态代理AspectCore的使用(三) 
  • 微服务——网关Ocelot Consul实现集群轮询(四)

澳门新萄京官方网站 49引入网关层后的整体架构设计

从代码结构来看,其基于业务边界(Marketing和Shopping)分别为Mobile和Web端建立多个网关项目,这样做利于隔离变化,降低耦合,且保证开发团队的独立自主性。所以我们在设计网关时也应注意到这一点,切忌设计大一统的单一API网关,以避免整个微服务架构体系的过度耦合。在网关设计中应当根据业务和领域去决定API网关的边界,尽量设计细粒度而非粗粒度的API网关。

eShopOnContainers中ApiGateways文件下是相关的网关项目。相关项目结构如下图所示。

澳门新萄京官方网站 50ApiGateways 代码结构

从代码结构看,有四个configuration.json文件,该文件就是ocelot的配置文件,其中主要包含两个节点:

{ "ReRoutes": [], "GlobalConfiguration": {}}

那4个独立的配置文件是怎样设计成4个独立的API网关的呢?在eShopOnContainers中,首先基于OcelotApiGw项目构建单个Ocelot API网关Docker容器镜像,然后在运行时,通过使用docker volume分别挂载不同路径下的configuration.json文件来启动不同类型的API-Gateway容器。示意图如下:

澳门新萄京官方网站 51重用Ocelot Docker镜像启动多个网关容器服务

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_ENVIRONMENT=Development - IdentityUrl=http://identity.api ports: - "5200:80" volumes: - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration

通过这种方式将API网关分成多个API网关,不仅可以同时重复使用相同的Ocelot Docker镜像,而且开发团队可以专注于团队所属微服务的开发,并通过独立的Ocelot配置文件来管理自己的API网关。

而关于Ocelot的代码集成,主要就是指定配置文件以及注册Ocelot中间件。核心代码如下:

public void ConfigureServices(IServiceCollection services){ //.. services.AddOcelot (new ConfigurationBuilder () .AddJsonFile (Path.Combine ("configuration", "configuration.json")) .Build ;}public void Configure(IApplicationBuilder app, IHostingEnvironment env){ //... app.UseOcelot;}

在单体应用中时,进行页面展示时,可以一次性关联查询所需的对象并返回,但是对于微服务应用来说,某一个页面的展示可能需要涉及多个微服务的数据,那如何进行将多个微服务的数据进行聚合呢?首先,不可否认的是,Ocelot提供了请求聚合功能,但是就其灵活性而言,远不能满足我们的需求。因此,一般会选择自定义聚合器来完成灵活的聚合功能。在eShopOnContainers中就是通过独立ASP.NET Core Web API项目来提供明确的聚合服务。Mobile.Shopping.HttpAggregatorWeb.Shopping.HttpAggregator即是用于提供自定义的请求聚合服务。

澳门新萄京官方网站 52使用聚合服务的架构

下面就以Web.Shopping.HttpAggregator项目为例来讲解自定义聚合的实现思路。首先,该网关项目是基于ASP.NET Web API构建。其代码结构如下图所示:

澳门新萄京官方网站 53Web.Shopping.HttpAggregator 自定义聚合服务代码结构

其核心思路是自定义网关服务借助HttpClient发起请求。我们来看一下BasketService的实现代码:

public class BasketService : IBasketService{ private readonly HttpClient _apiClient; private readonly ILogger<BasketService> _logger; private readonly UrlsConfig _urls; public BasketService(HttpClient httpClient,ILogger<BasketService> logger, IOptions<UrlsConfig> config) { _apiClient = httpClient; _logger = logger; _urls = config.Value; } public async Task<BasketData> GetById(string id) { var data = await _apiClient.GetStringAsync(_urls.Basket   UrlsConfig.BasketOperations.GetItemById; var basket = !string.IsNullOrEmpty ? JsonConvert.DeserializeObject<BasketData> : null; return basket; }}

代码中主要是通过构造函数注入HttpClient,然后方法中借助HttpClient实例发起相应请求。那HttpClient实例是如何注册的呢,我们来看下启动类里服务注册逻辑。

public static IServiceCollection AddApplicationServices(this IServiceCollection services){ //register delegating handlers services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); //register http services services.AddHttpClient<IBasketService, BasketService>() .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() .AddPolicyHandler(GetRetryPolicy .AddPolicyHandler(GetCircuitBreakerPolicy; services.AddHttpClient<ICatalogService, CatalogService>() .AddPolicyHandler(GetRetryPolicy .AddPolicyHandler(GetCircuitBreakerPolicy; services.AddHttpClient<IOrderApiClient, OrderApiClient>() .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() .AddPolicyHandler(GetRetryPolicy .AddPolicyHandler(GetCircuitBreakerPolicy; return services;}

从代码中可以看到主要做了三件事:

  1. 注册HttpClientAuthorizationDelegatingHandler负责为HttpClient构造Authorization请求头
  2. 注册IHttpContextAccessor用于获取HttpContext
  3. 为三个网关服务分别注册独立的HttpClient,其中IBasketServieIOrderApiClient需要认证,所以注册了HttpClientAuthorizationDelegatingHandler用于构造Authorization请求头。另外,分别注册了Polly的请求重试和断路器策略。

HttpClientAuthorizationDelegatingHandler是如何构造Authorization请求头的呢?直接看代码实现:

public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler{ private readonly IHttpContextAccessor _httpContextAccesor; public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor) { _httpContextAccesor = httpContextAccesor; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var authorizationHeader = _httpContextAccesor.HttpContext .Request.Headers["Authorization"]; if (!string.IsNullOrEmpty(authorizationHeader)) { request.Headers.Add("Authorization", new List<string>() { authorizationHeader }); } var token = await GetToken(); if (token != null) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); } return await base.SendAsync(request, cancellationToken); } async Task<string> GetToken() { const string ACCESS_TOKEN = "access_token"; return await _httpContextAccesor.HttpContext .GetTokenAsync(ACCESS_TOKEN); }}

代码实现也很简单:首先从_httpContextAccesor.HttpContext.Request.Headers["Authorization"]中取,若没有则从_httpContextAccesor.HttpContext.GetTokenAsync("access_token")澳门新萄京官方网站:polly微服务故障管理库,Consul服务意识在windows下轻松利用。中取,拿到访问令牌后,添加到请求头request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);即可。

这里你肯定有个疑问就是:为什么不是到Identity microservices去取访问令牌,而是直接从_httpContextAccesor.HttpContext.GetTokenAsync("access_token")中取访问令牌?

Good Question,因为对于网关项目而言,其本身也是需要认证的,在访问网关暴露的需要认证的API时,其已经同Identity microservices协商并获取到令牌,并将令牌内置到HttpContext中了。所以,对于同一个请求上下文,我们仅需将网关项目申请到的令牌传递下去即可。

不管是独立的微服务还是网关,认证和授权问题都是要考虑的。Ocelot允许我们直接在网关内的进行身份验证,如下图所示:

澳门新萄京官方网站 54网关内身份验证

因为认证授权作为微服务的交叉问题,所以将认证授权作为横切关注点设计为独立的微服务更符合关注点分离的思想。而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的启动配置中,就注册了AuthenticationProviderKey:IdentityApiKey的认证服务。

public void ConfigureServices (IServiceCollection services) { var identityUrl = _cfg.GetValue<string> ("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.GetValue<string> ("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 网关模式也有其缺点所在。

  1. 网关层与内部微服务间的高度耦合。
  2. 网关层可能出现单点故障。
  3. API网关可能导致性能瓶颈。
  4. API网关如果包含复杂的自定义逻辑和数据聚合,额外增加了团队的开发维护沟通成本。

虽然IT没有银弹,但eShopOnContainers中网关模式的应用案例至少指明了一种解决问题的思路。而至于在实战场景中的技术选型,适合的就是最好的。

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:澳门新萄京官方网站:polly微服务故障管理库,

关键词: