在上篇.Net微服務實踐(二):Ocelot介紹和快速開始中咱們介紹了Ocelot,建立了一個Ocelot Hello World程序,接下來,咱們會介紹Oclot的主要特性路由和另一個特性請求聚合。這些特性都是經過配置來實現的。html
{ "ReRoutes": [], "GlobalConfiguration": {} }
Ocelot的配置文件包含兩個節點: ReRoutes和GlobalConfiguration前端
Ocelot的完整配置項以下nginx
{ "DownstreamPathTemplate": "/", "UpstreamPathTemplate": "/", "UpstreamHttpMethod": [ "Get" ], "DownstreamHttpMethod": "", "DownstreamHttpVersion": "", "AddHeadersToRequest": {}, "AddClaimsToRequest": {}, "RouteClaimsRequirement": {}, "AddQueriesToRequest": {}, "RequestIdKey": "", "FileCacheOptions": { "TtlSeconds": 0, "Region": "" }, "ReRouteIsCaseSensitive": false, "ServiceName": "", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 51876, } ], "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 0, "DurationOfBreak": 0, "TimeoutValue": 0 }, "LoadBalancer": "", "RateLimitOptions": { "ClientWhitelist": [], "EnableRateLimiting": false, "Period": "", "PeriodTimespan": 0, "Limit": 0 }, "AuthenticationOptions": { "AuthenticationProviderKey": "", "AllowedScopes": [] }, "HttpHandlerOptions": { "AllowAutoRedirect": true, "UseCookieContainer": true, "UseTracing": true, "MaxConnectionsPerServer": 100 }, "DangerousAcceptAnyServerCertificateValidator": false }
完整配置項中的每一項具體含義和做用接下來會一一介紹,大的配置項的主要含義以下:git
在上一篇的hello world程序中使用的就是基本配置github
{ "ReRoutes": [ { "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ] } ], "GlobalConfiguration": { "BaseUrl": "http://localhost:5000" } }
在基本配置的示例中:要實現的功能就是將 http://localhost:5000/api/orders GET 請求路由到 http://localhost:5001/api/orders GETjson
在Ocelot中,能夠以{something}的形式將變量的佔位符添加到模板中。佔位符變量須要同時出如今DownstreamPathTemplate和UpstreamPathTemplate屬性中。請求時Ocelot將嘗試請求時進行替換api
{ "DownstreamPathTemplate": "/api/{everything}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5002 } ], "UpstreamPathTemplate": "/api/{everything}", "UpstreamHttpMethod": [ "Get" ] }
示例說明:全部http://localhost:5000/api/XXXXXX的請求都會路由到http://localhost:5002/api/XXXXXX
例如http://localhost:5000/api/products 路由到 http://localhost:5002/api/products
例如http://localhost:5000/api/products/1 路由到 http://localhost:5002/api/products/1緩存
驗證服務器
修改配置,運行示例程序, 訪問http://localhost:5000/api/products,返回了產品數據數據結構
注意:在添加Ocelot.json文件時 .AddJsonFile("Ocelot.json",false,true), 第三個參數是指定文件發生變化時,是否從新加載,示例程序中是true. 因此咱們只要修改運行目錄下的配置文件,不用從新運行示例程序。
既然佔位符能夠作通用匹配,天然而然就有一種配置能夠匹配全部請求
{ "DownstreamPathTemplate": "/{url}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5002 } ], "UpstreamPathTemplate": "/{url}", "UpstreamHttpMethod": [ "Get" ] }
示例說明: 轉發全部的請求到http://localhost:5002
驗證
修改配置,運行示例程序, 訪問http://localhost:5000/api/products,返回了產品數據
若是一個上游請求有多個路由配置都能匹配,到底該使用哪一個路由呢? 路由能夠配置優先級(Priority), 0最小,路由會使用優先級高的(說明:若是多個匹配路由優先級同樣,則按順序使用第一個)
[ApiController] public class CategoryController : ControllerBase { // GET: api/Product [Route("api/categories")] [HttpGet] public IEnumerable<string> Get() { return new string[] { "電子產品", "醫護用品" }; } }
{ "DownstreamPathTemplate": "/api/products", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5002 } ], "UpstreamPathTemplate": "/api/products", "UpstreamHttpMethod": [ "Get" ], "Priority": 0 }, { "DownstreamPathTemplate": "/api/categories", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5002 } ], "UpstreamPathTemplate": "/api/{everything}", "UpstreamHttpMethod": [ "Get" ], "Priority": 1 }
若是這時訪問http://localhost:5000/api/products, 你們猜一下,是返回產品數據仍是類別數據?
驗證
修改配置,運行示例程序, 訪問http://localhost:5000/api/products,返回了類別數據, 由於類別路由的優先級是1, 優先級更高
[Route("api/orders/{id}")] [HttpGet] public string Get(int id) { string order = string.Empty; switch(id) { case 1: order = "劉明的訂單"; break; case 2: order = "王天的訂單"; break; default: order = "沒有找到訂單"; break; } return order; }
{ "DownstreamPathTemplate": "/api/orders/{id}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders?id={id}", "UpstreamHttpMethod": [ "Get" ] }
咱們指望的結果是,當訪問http://localhost:5000/api/orders?id=1 (下游服務實際沒這個接口)時 路由到http://localhost:5001/api/orders/1返回訂單明細
驗證
修改配置,運行示例程序, 訪問http://localhost:5000/api/orders?id=1,返回了訂單明細數據
有一種場景,前端一個頁面,調用了多個API,要同時開多個鏈接幾回調用才能所有所須要的數據,爲了減小沒必要要的請求和開銷,Ocelot也支持請求聚合
{ "DownstreamPathTemplate": "/api/orders", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5001 } ], "UpstreamPathTemplate": "/api/orders", "UpstreamHttpMethod": [ "Get" ], "Key": "Orders" }, { "DownstreamPathTemplate": "/api/products", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5002 } ], "UpstreamPathTemplate": "/api/products", "UpstreamHttpMethod": [ "Get" ], "Priority": 0, "Key": "Products" }
你們注意一下,這和以前的配置有什麼區別? 區別就是再每個路由配置下多了一個 Key, Key的值能夠任意定義(但建議仍是按業務含義定義)
"Aggregates": [ { "ReRouteKeys": [ "Orders", "Products" ], "UpstreamPathTemplate": "/api/aggregates" } ]
注意Aggregates配置是和在ReRoutes配置平級的
{ "ReRoutes": [], "Aggregates": [], "GlobalConfiguration": {} }
示例說明: 當訪問http://localhost:5000/api/aggregates, 會同時返回訂單數據和產品數據
運行示例進行驗證
既然是多個請求聚合,那麼問題來了:
// GET: api/Product [Route("api/orders")] [HttpGet] public IEnumerable<string> Get() { throw new Exception("獲取全部訂單出錯"); }
再次運行示例,訪問http://localhost:5000/api/aggregates,Response是200, 可是body中Products節點是正常的產品數據,Orders節點裏面的數據是異常信息
若是默認的聚合返回的結果數據結構不是咱們想要的,想要修改怎麼辦?答案是使用自定義聚合
public class FakeDefinedAggregator : IDefinedAggregator { public FakeDefinedAggregator(FakeDepdendency dep) { } public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses) { var one = await responses[0].DownstreamResponse.Content.ReadAsStringAsync(); var two = await responses[1].DownstreamResponse.Content.ReadAsStringAsync(); var merge = $"{one}, {two}"; var headers = responses.SelectMany(x => x.DownstreamResponse.Headers).ToList(); return new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers, "some reason"); } }
services.AddOcelot() .AddSingletonDefinedAggregator<FakeDefinedAggregator>();
"Aggregates": [ { "ReRouteKeys": [ "Orders", "Products" ], "UpstreamPathTemplate": "/api/aggregates", "Aggregator": "FakeDefinedAggregator" } ],
與以前的配置相比,多了以下的配置,就是指定自定義聚合器的
"Aggregator": "FakeDefinedAggregator"
驗證
修改配置,運行示例程序, 訪問http://localhost:5000/api/aggregate, 驗證返回結果
本篇咱們介紹了Ocelot配置,只要特性路由,以及請求聚合。接下里咱們會介紹Ocelot的其餘特性:限流熔斷、負載均衡 .Net微服務實踐(四)[網關]:Ocelot限流熔斷、緩存以及負載均衡