Ocelot 配置學習筆記

Ocelot是一個用.NET Core實現而且開源的API網關,它功能強大,包括了:路由、請求聚合、服務發現、認證、鑑權、限流熔斷、並內置了負載均衡器與Service Fabric、Butterfly Tracing集成。這些功能只都只須要簡單的配置便可完成,下面咱們會對這些功能的配置一一進行說明。算法

 

在asp.net core 2.0裏經過nuget便可完成集成,或者命令行dotnet add package Ocelot以及經過vs2017 UI添加Ocelot nuget引用均可以。sql




Install-Package Ocelot

基本的配置信息。json

{
    "ReRoutes": [], "GlobalConfiguration": { "BaseUrl": "https://api.mybusiness.com" } }




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

配置依賴注入與中間件

在startup.cs中咱們首先須要引用兩個命名空間api

using Ocelot.DependencyInjection; using Ocelot.Middleware;

接下來就是添加依賴注入和中間件數組

public void ConfigureServices(IServiceCollection services) { services.AddOcelot(); }



說明:public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseOcelot().Wait(); }
  • Downstream是下游服務配置
  • UpStream是上游服務配置
  • Aggregates 服務聚合配置
  • ServiceName, LoadBalancer, UseServiceDiscovery 配置服務發現
  • AuthenticationOptions 配置服務認證
  • RouteClaimsRequirement 配置Claims鑑權
  • RateLimitOptions爲限流配置
  • FileCacheOptions 緩存配置
  • QosOptions 服務質量與熔斷
  • DownstreamHeaderTransform頭信息轉發
  • DownstreamPathTemplate:下游戲
  • DownstreamScheme:下游服務http schema
  • DownstreamHostAndPorts:下游服務的地址,若是使用LoadBalancer的話這裏能夠填多項
  • UpstreamPathTemplate: 上游也就是用戶輸入的請求Url模板
  • UpstreamHttpMethod: 上游請求http方法,可以使用數組
  • Prioirty優先級
    對多個產生衝突的路由設置優化級
  • 路由負載均衡

    當下遊服務有多個結點的時候,咱們能夠在DownstreamHostAndPorts中進行配置。緩存

    {
        "DownstreamPathTemplate": "/api/posts/{postId}", "DownstreamScheme": "https", "DownstreamHostAndPorts": [ { "Host": "10.0.1.10", "Port": 5000, }, { "Host": "10.0.1.11", "Port": 5000, } ], "UpstreamPathTemplate": "/posts/{postId}", "LoadBalancer": "LeastConnection", "UpstreamHttpMethod": [ "Put", "Delete" ] }

 

LoadBalancer將決定負載均衡的算法服務器

 

  • LeastConnection – 將請求發往最空閒的那個服務器
  • RoundRobin – 輪流發送
  • NoLoadBalance – 老是發往第一個請求或者是服務發現

    限流

 

對請求進行限流能夠防止下游服務器由於訪問過載而崩潰,這個功能就是咱們的張善友張隊進添加進去的。很是優雅的實現,咱們只須要在路由下加一些簡單的配置便可以完成。app

 

"RateLimitOptions": { "ClientWhitelist": [], "EnableRateLimiting": true, "Period": "1s", "PeriodTimespan": 1, "Limit": 1 }

 

  • ClientWihteList 白名單
  • EnableRateLimiting 是否啓用限流
  • Period 統計時間段:1s, 5m, 1h, 1d
  • PeroidTimeSpan 多少秒以後客戶端能夠重試
  • Limit 在統計時間段內容許的最大請求數量

 

在 GlobalConfiguration下咱們還能夠進行如下配置負載均衡

 

"RateLimitOptions": { "DisableRateLimitHeaders": false, "QuotaExceededMessage": "Customize Tips!", "HttpStatusCode": 999, "ClientIdHeader" : "Test" }

 

  • Http頭  X-Rate-Limit 和 Retry-After 是否禁用
  • QuotaExceedMessage 當請求過載被截斷時返回的消息
  • HttpStatusCode 當請求過載被截斷時返回的http status
  • ClientIdHeader 用來識別客戶端的請求頭,默認是 ClientId

    服務質量與熔斷

  • 熔斷的意思是中止將請求轉發到下游服務。當下遊服務已經出現故障的時候再請求也是功而返,而且增長下游服務器和API網關的負擔。這個功能是用的Pollly來實現的,咱們只須要爲路由作一些簡單配置便可asp.net

    "QoSOptions": { "ExceptionsAllowedBeforeBreaking":3, "DurationOfBreak":5, "TimeoutValue":5000 }
  • ExceptionsAllowedBeforeBreaking 容許多少個異常請求
  • DurationOfBreak 熔斷的時間,單位爲秒
  • TimeoutValue 若是下游請求的處理時間超過多少則自如將請求設置爲超時

 

認證

 

若是咱們須要對下游API進行認證以及鑑權服務的,則首先Ocelot 網關這裏須要添加認證服務。這和咱們給一個單獨的API或者ASP.NET Core Mvc添加認證服務沒有什麼區別。

 

public void ConfigureServices(IServiceCollection services) { var authenticationProviderKey = "TestKey"; services.AddAuthentication() .AddJwtBearer(authenticationProviderKey, x => { }); }

 

而後在ReRoutes的路由模板中的AuthenticationOptions進行配置,只須要咱們的AuthenticationProviderKey一致便可。

 

"ReRoutes": [{ "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 51876, } ], "DownstreamPathTemplate": "/", "UpstreamPathTemplate": "/", "UpstreamHttpMethod": ["Post"], "ReRouteIsCaseSensitive": false, "DownstreamScheme": "http", "AuthenticationOptions": { "AuthenticationProviderKey": "TestKey", "AllowedScopes": [] } }]

 

JWT Tokens

 

要讓網關支持JWT 的認證其實和讓API支持JWT  Token的認證是同樣的

 

public void ConfigureServices(IServiceCollection services) { var authenticationProviderKey = "TestKey"; services.AddAuthentication() .AddJwtBearer(authenticationProviderKey, x => { x.Authority = "test"; x.Audience = "test"; }); services.AddOcelot(); }

 

Identity Server Bearer Tokens

 

添加Identity Server的認證也是同樣

 

public void ConfigureServices(IServiceCollection services) { var authenticationProviderKey = "TestKey"; var options = o => { o.Authority = "https://whereyouridentityserverlives.com"; o.ApiName = "api"; o.SupportedTokens = SupportedTokens.Both; o.ApiSecret = "secret"; }; services.AddAuthentication() .AddIdentityServerAuthentication(authenticationProviderKey, options); services.AddOcelot(); }

 

Allowed Scopes

 

這裏的Scopes將從當前 token 中的 claims中來獲取,咱們的鑑權服務將依靠於它來實現 。當前路由的下游API須要某個權限時,咱們須要在這裏聲明 。和oAuth2中的 scope意義一致。

 

鑑權

 

咱們經過認證中的AllowedScopes 拿到claims以後,若是要進行權限的鑑別須要添加如下配置

 

"RouteClaimsRequirement": { "UserType": "registered" }

 

當前請求上下文的token中所帶的claims若是沒有 name=」UserType」 而且 value=」registered」 的話將沒法訪問下游服務。

 

請求頭轉化

 

請求頭轉發分兩種:轉化以後傳給下游和從下游接收轉化以後傳給客戶端。在Ocelot的配置裏面叫作Pre  Downstream Request和Post Downstream Request。目前的轉化只支持查找和替換。咱們用到的配置主要是 UpstreamHeaderTransform 和 DownstreamHeaderTransform

 

Pre Downstream Request

 

"Test": "http://www.bbc.co.uk/, http://ocelot.com/"

 

好比咱們將客戶端傳過來的Header中的 Test 值改成 http://ocelot.com/以後再傳給下游

 

"UpstreamHeaderTransform": { "Test": "http://www.bbc.co.uk/, http://ocelot.com/" },

 

Post Downstream Request

 

而咱們一樣能夠將下游Header中的Test再轉爲 http://www.bbc.co.uk/以後再轉給客戶端。

 

"DownstreamHeaderTransform": { "Test": "http://www.bbc.co.uk/, http://ocelot.com/" },

 

變量

 

在請求頭轉化這裏Ocelot爲咱們提供了兩個變量:BaseUrl和DownstreamBaseUrl。BaseUrl就是咱們在GlobalConfiguration裏面配置的BaseUrl,後者是下游服務的Url。這裏用301跳轉作一個示例如何使用這兩個變量。

 

默認的301跳轉,咱們會返回一個Location的頭,因而咱們但願將http://www.bbc.co.uk 替換爲 http://ocelot.com,後者者網關對外的域名。

 

"DownstreamHeaderTransform": { "Location": "http://www.bbc.co.uk/, http://ocelot.com/" }, "HttpHandlerOptions": { "AllowAutoRedirect": false, },

 

咱們經過DownstreamHeaderTranfrom將下游返回的請求頭中的Location替換爲了網關的域名,而不是下游服務的域名。因此在這裏咱們也可使用BaseUrl來作爲變量替換。

 

"DownstreamHeaderTransform": { "Location": "http://localhost:6773, {BaseUrl}" }, "HttpHandlerOptions": { "AllowAutoRedirect": false, },

 

當咱們的下游服務有多個的時候,咱們就沒有辦法找到前面的那個http://localhost:6773,由於它多是多個值。因此這裏咱們可使用DownstreamBaseUrl。

 

"DownstreamHeaderTransform": { "Location": "{DownstreamBaseUrl}, {BaseUrl}" }, "HttpHandlerOptions": { "AllowAutoRedirect": false, },


Claims轉化

Claims轉化

 

 

Claims轉化功能能夠將Claims中的值轉化到請求頭、Query String、或者下游的Claims中,對於Claims的轉化,比較特殊的一點是它提供了一種對字符串進行解析的方法。舉個例子,好比咱們有一個sub的claim。這個claims的 name=」sub」 value=」usertypevalue|useridvalue」,實際上咱們不會弄這麼複雜的value,它是拼接來的,可是咱們爲了演示這個字符串解析的功能,因此使用了這麼一個複雜的value。

 

Ocelot爲咱們提供的功能分爲三段,第一段是Claims[sub],很好理解[] 裏面是咱們的claim的名稱。第二段是  > 表示對字符串進行拆分, 後面跟着拆分完以後咱們要取的那個數組裏面的某一個元素用 value[index]來表示,取第0位元素也能夠直接用value。第三段也是以 > 開頭後面跟着咱們的分隔符,在咱們上面的例子分隔符是 |

 

因此在這裏若是咱們要取  usertype這個claim就會這樣寫: Claims[sub] > value[0] > |

 

Claim取到以後咱們若是要放到請求頭、QueryString、以及Claim當中對應有如下三個配置。

 

Claims to Claims 

 

"AddClaimsToRequest": { "UserType": "Claims[sub] > value[0] > |", "UserId": "Claims[sub] > value[1] > |" }

 

Claims to Headers 

 

"AddHeadersToRequest": { "CustomerId": "Claims[sub] > value[1] > |" }

 

這裏咱們仍是用的上面那個 sub = usertypevalue|useridvalue 的claim來進行處理和轉化。

 

Claims to Query String

 

"AddQueriesToRequest": { "LocationId": "Claims[LocationId] > value", }

 

這裏沒有進行分隔,因此直接取了value。

 

NanoFabric 配置

  1 {
  2   "ReRoutes": [
  3     {
  4       "DownstreamPathTemplate": "/api/values",
  5       "DownstreamScheme": "http",
  6       "UpstreamPathTemplate": "/api/values",
  7       "UpstreamHttpMethod": [ "Get" ],
  8       "ServiceName": "SampleService_Kestrel",
  9       "LoadBalancerOptions": {
 10         "Type": "LeastConnection"
 11       },
 12       "UseServiceDiscovery": true,
 13       "FileCacheOptions": { "TtlSeconds": 15 }
 14     },
 15     {
 16       "DownstreamPathTemplate": "/",
 17       "DownstreamScheme": "http",
 18       "DownstreamHostAndPorts": [
 19         {
 20           "Host": "localhost",
 21           "Port": 52876
 22         }
 23       ],
 24       "UpstreamPathTemplate": "/identityserverexample",
 25       "UpstreamHttpMethod": [ "Get" ],
 26       "QoSOptions": {
 27         "ExceptionsAllowedBeforeBreaking": 3,
 28         "DurationOfBreak": 10,
 29         "TimeoutValue": 5000
 30       },
 31       "AuthenticationOptions": {
 32         "AuthenticationProviderKey": "TestKey",
 33         "AllowedScopes": [
 34           "openid",
 35           "offline_access"
 36         ]
 37       },
 38       "AddHeadersToRequest": {
 39         "CustomerId": "Claims[CustomerId] > value",
 40         "LocationId": "Claims[LocationId] > value",
 41         "UserType": "Claims[sub] > value[0] > |",
 42         "UserId": "Claims[sub] > value[1] > |"
 43       },
 44       "AddClaimsToRequest": {
 45         "CustomerId": "Claims[CustomerId] > value",
 46         "LocationId": "Claims[LocationId] > value",
 47         "UserType": "Claims[sub] > value[0] > |",
 48         "UserId": "Claims[sub] > value[1] > |"
 49       },
 50       "AddQueriesToRequest": {
 51         "CustomerId": "Claims[CustomerId] > value",
 52         "LocationId": "Claims[LocationId] > value",
 53         "UserType": "Claims[sub] > value[0] > |",
 54         "UserId": "Claims[sub] > value[1] > |"
 55       },
 56       "RouteClaimsRequirement": {
 57         "UserType": "registered"
 58       },
 59       "RequestIdKey": "OcRequestId"
 60     },
 61     {
 62       "DownstreamPathTemplate": "/posts",
 63       "DownstreamScheme": "https",
 64       "DownstreamHostAndPorts": [
 65         {
 66           "Host": "jsonplaceholder.typicode.com",
 67           "Port": 443
 68         }
 69       ],
 70       "UpstreamPathTemplate": "/posts",
 71       "UpstreamHttpMethod": [ "Get" ],
 72       "QoSOptions": {
 73         "ExceptionsAllowedBeforeBreaking": 3,
 74         "DurationOfBreak": 10,
 75         "TimeoutValue": 5000
 76       }
 77     },
 78     {
 79       "DownstreamPathTemplate": "/posts/{postId}",
 80       "DownstreamScheme": "http",
 81       "DownstreamHostAndPorts": [
 82         {
 83           "Host": "jsonplaceholder.typicode.com",
 84           "Port": 80
 85         }
 86       ],
 87       "UpstreamPathTemplate": "/posts/{postId}",
 88       "UpstreamHttpMethod": [ "Get" ],
 89       "RequestIdKey": "ReRouteRequestId",
 90       "QoSOptions": {
 91         "ExceptionsAllowedBeforeBreaking": 3,
 92         "DurationOfBreak": 10,
 93         "TimeoutValue": 5000
 94       }
 95     },
 96     {
 97       "DownstreamPathTemplate": "/posts/{postId}/comments",
 98       "DownstreamScheme": "http",
 99       "DownstreamHostAndPorts": [
100         {
101           "Host": "jsonplaceholder.typicode.com",
102           "Port": 80
103         }
104       ],
105       "UpstreamPathTemplate": "/posts/{postId}/comments",
106       "UpstreamHttpMethod": [ "Get" ],
107       "QoSOptions": {
108         "ExceptionsAllowedBeforeBreaking": 3,
109         "DurationOfBreak": 10,
110         "TimeoutValue": 5000
111       }
112     },
113     {
114       "DownstreamPathTemplate": "/comments",
115       "DownstreamScheme": "http",
116       "DownstreamHostAndPorts": [
117         {
118           "Host": "jsonplaceholder.typicode.com",
119           "Port": 80
120         }
121       ],
122       "UpstreamPathTemplate": "/comments",
123       "UpstreamHttpMethod": [ "Get" ],
124       "QoSOptions": {
125         "ExceptionsAllowedBeforeBreaking": 3,
126         "DurationOfBreak": 10,
127         "TimeoutValue": 5000
128       }
129     },
130     {
131       "DownstreamPathTemplate": "/posts",
132       "DownstreamScheme": "http",
133       "DownstreamHostAndPorts": [
134         {
135           "Host": "jsonplaceholder.typicode.com",
136           "Port": 80
137         }
138       ],
139       "UpstreamPathTemplate": "/posts",
140       "UpstreamHttpMethod": [ "Post" ],
141       "QoSOptions": {
142         "ExceptionsAllowedBeforeBreaking": 3,
143         "DurationOfBreak": 10,
144         "TimeoutValue": 5000
145       }
146     },
147     {
148       "DownstreamPathTemplate": "/posts/{postId}",
149       "DownstreamScheme": "http",
150       "DownstreamHostAndPorts": [
151         {
152           "Host": "jsonplaceholder.typicode.com",
153           "Port": 80
154         }
155       ],
156       "UpstreamPathTemplate": "/posts/{postId}",
157       "UpstreamHttpMethod": [ "Put" ],
158       "QoSOptions": {
159         "ExceptionsAllowedBeforeBreaking": 3,
160         "DurationOfBreak": 10,
161         "TimeoutValue": 5000
162       }
163     },
164     {
165       "DownstreamPathTemplate": "/posts/{postId}",
166       "DownstreamScheme": "http",
167       "DownstreamHostAndPorts": [
168         {
169           "Host": "jsonplaceholder.typicode.com",
170           "Port": 80
171         }
172       ],
173       "UpstreamPathTemplate": "/posts/{postId}",
174       "UpstreamHttpMethod": [ "Patch" ],
175       "QoSOptions": {
176         "ExceptionsAllowedBeforeBreaking": 3,
177         "DurationOfBreak": 10,
178         "TimeoutValue": 5000
179       }
180     },
181     {
182       "DownstreamPathTemplate": "/posts/{postId}",
183       "DownstreamScheme": "http",
184       "DownstreamHostAndPorts": [
185         {
186           "Host": "jsonplaceholder.typicode.com",
187           "Port": 80
188         }
189       ],
190       "UpstreamPathTemplate": "/posts/{postId}",
191       "UpstreamHttpMethod": [ "Delete" ],
192       "QoSOptions": {
193         "ExceptionsAllowedBeforeBreaking": 3,
194         "DurationOfBreak": 10,
195         "TimeoutValue": 5000
196       }
197     },
198     {
199       "DownstreamPathTemplate": "/api/products",
200       "DownstreamScheme": "http",
201       "DownstreamHostAndPorts": [
202         {
203           "Host": "jsonplaceholder.typicode.com",
204           "Port": 80
205         }
206       ],
207       "UpstreamPathTemplate": "/products",
208       "UpstreamHttpMethod": [ "Get" ],
209       "QoSOptions": {
210         "ExceptionsAllowedBeforeBreaking": 3,
211         "DurationOfBreak": 10,
212         "TimeoutValue": 5000
213       },
214       "FileCacheOptions": { "TtlSeconds": 15 }
215     },
216     {
217       "DownstreamPathTemplate": "/api/products/{productId}",
218       "DownstreamScheme": "http",
219       "DownstreamHostAndPorts": [
220         {
221           "Host": "jsonplaceholder.typicode.com",
222           "Port": 80
223         }
224       ],
225       "UpstreamPathTemplate": "/products/{productId}",
226       "UpstreamHttpMethod": [ "Get" ],
227       "FileCacheOptions": { "TtlSeconds": 15 }
228     },
229     {
230       "DownstreamPathTemplate": "/api/products",
231       "DownstreamScheme": "http",
232       "DownstreamHostAndPorts": [
233         {
234           "Host": "jsonplaceholder.typicode.com",
235           "Port": 80
236         }
237       ],
238       "UpstreamPathTemplate": "/products",
239       "UpstreamHttpMethod": [ "Post" ],
240       "QoSOptions": {
241         "ExceptionsAllowedBeforeBreaking": 3,
242         "DurationOfBreak": 10,
243         "TimeoutValue": 5000
244       }
245     },
246     {
247       "DownstreamPathTemplate": "/api/products/{productId}",
248       "DownstreamScheme": "http",
249       "DownstreamHostAndPorts": [
250         {
251           "Host": "jsonplaceholder.typicode.com",
252           "Port": 80
253         }
254       ],
255       "UpstreamPathTemplate": "/products/{productId}",
256       "UpstreamHttpMethod": [ "Put" ],
257       "QoSOptions": {
258         "ExceptionsAllowedBeforeBreaking": 3,
259         "DurationOfBreak": 10,
260         "TimeoutValue": 5000
261       },
262       "FileCacheOptions": { "TtlSeconds": 15 }
263     },
264     {
265       "DownstreamPathTemplate": "/posts",
266       "DownstreamScheme": "http",
267       "DownstreamHostAndPorts": [
268         {
269           "Host": "jsonplaceholder.typicode.com",
270           "Port": 80
271         }
272       ],
273       "UpstreamPathTemplate": "/posts/",
274       "UpstreamHttpMethod": [ "Get" ],
275       "QoSOptions": {
276         "ExceptionsAllowedBeforeBreaking": 3,
277         "DurationOfBreak": 10,
278         "TimeoutValue": 5000
279       },
280       "FileCacheOptions": { "TtlSeconds": 15 }
281     },
282     {
283       "DownstreamPathTemplate": "/",
284       "DownstreamScheme": "http",
285       "DownstreamHostAndPorts": [
286         {
287           "Host": "www.bbc.co.uk",
288           "Port": 80
289         }
290       ],
291       "UpstreamPathTemplate": "/bbc/",
292       "UpstreamHttpMethod": [ "Get" ]
293     }
294   ],
295   "GlobalConfiguration": {
296     "RequestIdKey": "ot-traceid",
297     "BaseUrl": "http://localhost:8000",
298     "ServiceDiscoveryProvider": {
299       "Host": "localhost",
300       "Port": 8500
301     }
302   }
303 }
相關文章
相關標籤/搜索