作者:依樂祝
原文地址:https://www.cnblogs.com/yilezhu/p/9664977.html
上篇《Ocelot簡易教程(二)之快速開始2》教大家如何快速跑起來一個ocelot實例項目,也只是簡單的對Ocelot進行了配置,這篇文章會給大家詳細的介紹一下Ocelot的配置信息。希望能對大家深入使用Ocelot有所幫助。
上篇中也提到了,最簡單的Ocelot如下面所示,只有簡單的兩個節點,一個是ReRoutes
,另一個就是GlobalConfiguration
關於這兩個節點的作用,上篇也已經講述了,這里再簡單的講下ReRoutes:告訴Ocelot如何處理上游的請求。GlobalConfiguration:顧名思義就是全局配置,此節點的配置允許覆蓋ReRoutes里面的配置,你可以在這里進行通用的一些配置信息。
{
"ReRoutes": [],
"GlobalConfiguration": {}
}
下面呢給出ReRoute 的所有的配置信息,當然在實際使用的時候你沒有必要全部進行配置,只需要根據你項目的實際需要進行相關的配置就可以了。
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",//下游路由模板
"UpstreamPathTemplate": "/good/{everything}",//上游路由模板
"UpstreamHttpMethod": [ "Get", "Post" ],//上游請求方法
"AddHeadersToRequest": {},
"UpstreamHeaderTransform": {},
"DownstreamHeaderTransform": {},
"AddClaimsToRequest": {},
"RouteClaimsRequirement": {},
"AddQueriesToRequest": {},
"RequestIdKey": null,
"FileCacheOptions": {
"TtlSeconds": 0,
"Region": null
},
"ReRouteIsCaseSensitive": false,
"ServiceName": null,
"DownstreamScheme": "http",
"QoSOptions": {//Qos相關配置
"ExceptionsAllowedBeforeBreaking": 0,
"DurationOfBreak": 0,
"TimeoutValue": 0
},
"LoadBalancerOptions": {//負載均衡相關選項
"Type": "RoundRobin",
"Key": null,
"Expiry": 0
},
"RateLimitOptions": {//限流相關配置
"ClientWhitelist": [],
"EnableRateLimiting": false,
"Period": null,
"PeriodTimespan": 0.0,
"Limit": 0
},
"AuthenticationOptions": {//認證相關選項
"AuthenticationProviderKey": null,
"AllowedScopes": []
},
"HttpHandlerOptions": {//HttpHandler相關的配置
"AllowAutoRedirect": false,//是否對下游重定向進行響應
"UseCookieContainer": false,//是否啟動CookieContainer儲存cookies
"UseTracing": false,
"UseProxy": true
},
"DownstreamHostAndPorts": [//下游端口及host
{
"Host": "localhost",
"Port": 1001
},
{
"Host": "localhost",
"Port": 1002
}
],
"UpstreamHost": null,//上游Host
"Key": null,
"DelegatingHandlers": [],
"Priority": 1,
"Timeout": 0,
"DangerousAcceptAnyServerCertificateValidator": false
}
當然上面的配置項我就不一一的進行介紹,因為很多配置相信大家根據意思都能知道個大概了。我只會對比較常用的配置做下介紹。而且在接下來的文章中對對每個節點進行單獨的詳細的介紹。在介紹之前呢先看Ocelot的幾個特性。
Ocelot特性介紹
合並配置文件
這個特性允許用戶創建多個配置文件來方便的對大型項目進行配置。試想一下,如果你的項目有幾十個路由規則需要配置的話,那么在一個配置文件進行配置應該很痛苦吧,有了這個特性后,你就可以創建多個配置文件。Ocelot會自動合並他們。
在加載配置文件的時候 你可以通過下面的方式來調用AddOcelot()方法來替換直接加載某個配置的寫法 如:AddJsonFile(“ocelot.json”)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddOcelot()
.AddEnvironmentVariables();
})
在這種情況下,Ocelot會尋找所有匹配了 (?i)ocelot.([a-zA-Z0-9]*).json
的文件,然后合並他們。如何你要設置GlobalConfiguration 屬性,那么你需要建立一個ocelot.global.json 的文件來進行全局的配置。
這里上一個例子吧!可以方便大家的理解。
新建一個ocelot.good.json文件,並加入下面的配置:
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001
},
{
"Host": "localhost",
"Port": 1002
}
],
"UpstreamPathTemplate": "/good/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
]
}
然后再新建一個ocelot.order.json文件,並加入下面的配置:
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001
},
{
"Host": "localhost",
"Port": 1002
}
],
"UpstreamPathTemplate": "/order/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
]
}
最后新建一個ocelot.all.json文件,並把上篇文章中的路由拷貝到里面:
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001
},
{
"Host": "localhost",
"Port": 1002
}
],
"UpstreamPathTemplate": "/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
],
"GlobalConfiguration": {
}
}
然后修改下,Program.cs文件中的代碼如下:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddOcelot()
.AddEnvironmentVariables();
})
.UseUrls("http://localhost:1000")
.UseStartup<Startup>();
這里最重要的代碼就是config.AddOcelot()
了。這段代碼就會按照上面的規則查找所有符合條件的文件並合並路由。合並后的代碼如下:
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"UpstreamPathTemplate": "/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"AddHeadersToRequest": {},
"UpstreamHeaderTransform": {},
"DownstreamHeaderTransform": {},
"AddClaimsToRequest": {},
"RouteClaimsRequirement": {},
"AddQueriesToRequest": {},
"RequestIdKey": null,
"FileCacheOptions": {
"TtlSeconds": 0,
"Region": null
},
"ReRouteIsCaseSensitive": false,
"ServiceName": null,
"DownstreamScheme": "http",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 0,
"DurationOfBreak": 0,
"TimeoutValue": 0
},
"LoadBalancerOptions": {
"Type": "RoundRobin",
"Key": null,
"Expiry": 0
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": false,
"Period": null,
"PeriodTimespan": 0.0,
"Limit": 0
},
"AuthenticationOptions": {
"AuthenticationProviderKey": null,
"AllowedScopes": []
},
"HttpHandlerOptions": {
"AllowAutoRedirect": false,
"UseCookieContainer": false,
"UseTracing": false,
"UseProxy": true
},
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001
},
{
"Host": "localhost",
"Port": 1002
}
],
"UpstreamHost": null,
"Key": null,
"DelegatingHandlers": [],
"Priority": 1,
"Timeout": 0,
"DangerousAcceptAnyServerCertificateValidator": false
},
{
"DownstreamPathTemplate": "/api/{everything}",
"UpstreamPathTemplate": "/good/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"AddHeadersToRequest": {},
"UpstreamHeaderTransform": {},
"DownstreamHeaderTransform": {},
"AddClaimsToRequest": {},
"RouteClaimsRequirement": {},
"AddQueriesToRequest": {},
"RequestIdKey": null,
"FileCacheOptions": {
"TtlSeconds": 0,
"Region": null
},
"ReRouteIsCaseSensitive": false,
"ServiceName": null,
"DownstreamScheme": "http",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 0,
"DurationOfBreak": 0,
"TimeoutValue": 0
},
"LoadBalancerOptions": {
"Type": "RoundRobin",
"Key": null,
"Expiry": 0
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": false,
"Period": null,
"PeriodTimespan": 0.0,
"Limit": 0
},
"AuthenticationOptions": {
"AuthenticationProviderKey": null,
"AllowedScopes": []
},
"HttpHandlerOptions": {
"AllowAutoRedirect": false,
"UseCookieContainer": false,
"UseTracing": false,
"UseProxy": true
},
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001
},
{
"Host": "localhost",
"Port": 1002
}
],
"UpstreamHost": null,
"Key": null,
"DelegatingHandlers": [],
"Priority": 1,
"Timeout": 0,
"DangerousAcceptAnyServerCertificateValidator": false
},
{
"DownstreamPathTemplate": "/api/{everything}",
"UpstreamPathTemplate": "/order/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"AddHeadersToRequest": {},
"UpstreamHeaderTransform": {},
"DownstreamHeaderTransform": {},
"AddClaimsToRequest": {},
"RouteClaimsRequirement": {},
"AddQueriesToRequest": {},
"RequestIdKey": null,
"FileCacheOptions": {
"TtlSeconds": 0,
"Region": null
},
"ReRouteIsCaseSensitive": false,
"ServiceName": null,
"DownstreamScheme": "http",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 0,
"DurationOfBreak": 0,
"TimeoutValue": 0
},
"LoadBalancerOptions": {
"Type": "RoundRobin",
"Key": null,
"Expiry": 0
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": false,
"Period": null,
"PeriodTimespan": 0.0,
"Limit": 0
},
"AuthenticationOptions": {
"AuthenticationProviderKey": null,
"AllowedScopes": []
},
"HttpHandlerOptions": {
"AllowAutoRedirect": false,
"UseCookieContainer": false,
"UseTracing": false,
"UseProxy": true
},
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001
},
{
"Host": "localhost",
"Port": 1002
}
],
"UpstreamHost": null,
"Key": null,
"DelegatingHandlers": [],
"Priority": 1,
"Timeout": 0,
"DangerousAcceptAnyServerCertificateValidator": false
}
],
"DynamicReRoutes": [],
"Aggregates": [],
"GlobalConfiguration": {
"RequestIdKey": null,
"ServiceDiscoveryProvider": {
"Host": null,
"Port": 0,
"Type": null,
"Token": null,
"ConfigurationKey": null,
"PollingInterval": 0
},
"RateLimitOptions": {
"ClientIdHeader": "ClientId",
"QuotaExceededMessage": null,
"RateLimitCounterPrefix": "ocelot",
"DisableRateLimitHeaders": false,
"HttpStatusCode": 429
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 0,
"DurationOfBreak": 0,
"TimeoutValue": 0
},
"BaseUrl": null,
"LoadBalancerOptions": {
"Type": null,
"Key": null,
"Expiry": 0
},
"DownstreamScheme": null,
"HttpHandlerOptions": {
"AllowAutoRedirect": false,
"UseCookieContainer": false,
"UseTracing": false,
"UseProxy": true
}
}
}
Ocelot的合並方式是先對滿足格式的文件遍歷查找,然后循環加載他們,並提取所有的ReRoutes以及AggregateReRoutes 的數據。如果發現ocelot.global.json ,則添加到GlobalConfiguration 中。然后Ocelto會將合並后的配置保存在ocelot.json的文件中,當Ocelot運行時會加載這個合並后的ocelot.json文件,從而加載了所有的配置。
注意:這里需要注意的是Ocelot在合並的過程中不會對內容進行驗證,只有在最終合並的配置進行校驗,所以如果發現問題的話,那么你需要檢查最終生成的ocelot.json 是否出錯了!
在consul中存儲配置
這里你首先要做的就是安裝Ocelot中提供的Consul的NuGet包,Nuget安裝方式:
Install-Package Ocelot.Provider.Consul
然后在注冊服務時添加如下內容:Ocelot將會嘗試在Consul KV存儲並加載配置。
services
.AddOcelot()
.AddConsul()
.AddConfigStoredInConsul();
當然你還得把下面的配置添加到你的ocelot.json文件中。這里定義Ocelot如何查找Consul根並從Consul中加載並存儲配置.
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 9500
}
}
變化時重新加載配置文件
Ocelot支持在配置文件發生改變的時候重新加載json配置文件。在加載ocelot.json文件的時候按照下面進行配置,那么當你手動更新ocelot.json文件時,Ocelot將重新加載ocelot.json配置文件。
config.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
配置Key
如果你使用Consul進行配置,你可能需要配置Key以便區分多個配置,為了指定Key,你需要在json配置文件中的ServiceDiscoveryProvider部分設置ConfigurationKey屬性:
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 9500,
"ConfigurationKey": "Oceolot_A"
}
}
在此實例中,Ocelot將會在Consul查找時使用Oceolot_A 作為配置的Key.如果沒有設置ConfigurationKey 則Ocelot將使用字符串InternalConfiguration 作為此配置的Key
跟蹤重定向和使用CookieContainer
在ReRoute配置中可以使用HttpHandlerOptions來設置HttpHandler行為:
- AllowAutoRedirect是一個值,指示請求是否應遵循重定向響應。如果請求應自動遵循來自下游資源的重定向響應,則將其設置為true; 否則是假的。默認值為false。
- UseCookieContainer是一個值,指示處理程序是否使用CookieContainer屬性存儲服務器cookie並在發送請求時使用這些cookie。默認值為false。請注意,如果您使CookieContainer,則Ocelot會為每個下游服務緩存HttpClient。這意味着對該DownstreamService的所有請求將共享相同的cookie。
SSL 錯誤處理
如果你想忽略SSL 警告/錯誤,你可以在你的ReRoute 配置中加上如下配置:
"DangerousAcceptAnyServerCertificateValidator": false
當然作者是不建議這樣做的,最好的方式是創建你本地以及遠程所信任的證書。
Ocelot路由詳解
路由
Ocelot的最主要的功能是接收傳入的http請求並將其轉發到下游服務。
Ocelot使用ReRoute節點描述將一個請求路由到另一個請求。為了讓路由在Ocelot中起作用,您需要在配置中設置ReRoute:
{
"ReRoutes": [
]
}
要配置ReRoute,您需要在ReRoutes json數組中至少添加一個:
{
"DownstreamPathTemplate": "/api/good/{goodId}",//下游路由模板
"DownstreamScheme": "http",//下游路由請求的方式
"DownstreamHostAndPorts": [//下游路由的Host以及端口
{
"Host": "localhost",
"Port": 1001,
}
],
"UpstreamPathTemplate": "/good/{goodId}",//上游路由請求的模板
"UpstreamHttpMethod": [ "Put", "Delete" ]//上游路由請求的方式
}
DownstreamPathTemplate,DownstreamScheme和DownstreamHostAndPorts定義請求將轉發到的URL。
DownstreamHostAndPorts是一個集合,用於定義您希望將請求轉發到的任何下游服務的主機和端口。通常這只包含一個條目,但有時你希望對下游請求服務進行負載均衡,這個時候你就可以添加多個條目,並配合負載均衡選項進行相關的負載均衡設置。
UpstreamPathTemplate是Ocelot用於標識要用於給定請求的DownstreamPathTemplate對應的URL。使用UpstreamHttpMethod以便Ocelot可以區分具有不同HTTP謂詞的請求到相同的URL。您可以設置特定的HTTP方法列表,也可以設置一個空列表以允許所有的。
在Ocelot中,您可以以{something}的形式將變量的占位符添加到模板中。占位符變量需要同時出現在DownstreamPathTemplate和UpstreamPathTemplate屬性中。請求時Ocelot將嘗試請求時進行替換。
你也可以像下面這樣配置,捕獲所有的路由:
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001,
},
{
"Host": "localhost",
"Port": 1002,
}
],
"UpstreamPathTemplate": "/{everything}",
"UpstreamHttpMethod": [ "Get", "Post" ]
}
這個配置將會把路徑+查詢字符串統統轉發到下游路由.
注意:默認的ReRouting的配置是不區分大小寫的,如果需要修改此配置,可以通過下面進行配置:
"ReRouteIsCaseSensitive": true
這意味着Ocelot將嘗試將傳入的上游URL與上游模板匹配時,區分大小寫。
全部捕獲
Ocelot的路由還支持捕獲所有樣式路由,用戶可以指定他們想要匹配所有請求。
如果您設置如下所示的配置,則所有請求都將直接代理。占位符{url}名稱不重要,任何名稱都可以使用。
{
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001,
}
],
"UpstreamPathTemplate": "/{url}",
"UpstreamHttpMethod": [ "Get" ]
}
上面配置的全部捕獲的優先級低於任何其他法人ReRoute。如果您的配置中還有下面的ReRoute,那么Ocelot會在全部捕獲之前匹配它。
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001,
}
],
"UpstreamPathTemplate": "/",
"UpstreamHttpMethod": [ "Get" ]
}
上游主機
此功能允許您根據上游主機獲得ReRoutes。這通過查看客戶端使用的主機頭,然后將其用作我們用於識別ReRoute的信息的一部分來工作。
要使用此功能,請在配置中添加以下內容。
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 1001,
}
],
"UpstreamPathTemplate": "/",
"UpstreamHttpMethod": [ "Get" ],
"UpstreamHost": "yilezhu.cn"
}
僅當主機標頭值為yilezhu.cn時,才會匹配上面的ReRoute。
如果您沒有在ReRoute上設置UpstreamHost,那么任何主機頭都將與之匹配。這意味着如果你有兩個相同的ReRoutes,除了UpstreamHost,其中一個為null而另一個不為null 那么Ocelot將支持已設置的那個。
優先級
你可以通過ocelot.json文件的ReRoutes節點中的Priorty屬性來設置匹配上游HttpRequest的優先級順序
比如,下面兩個路由:
{
"UpstreamPathTemplate": "/goods/{catchAll}"
"Priority": 0
}
以及
{
"UpstreamPathTemplate": "/goods/delete"
"Priority": 1
}
上面兩個路由中,如果向Ocelot發出的請求時/goods/delete
格式的話,則Ocelot會優先匹配/goods /delete
的路由。
動態路由
作者的想法是在使用服務發現提供程序時啟用動態路由,這樣您就不必提供ReRoute的配置。我們會在服務發現那一章進行詳細的介紹。
查詢字符串
Ocelot允許您指定一個查詢字符串作為DownstreamPathTemplate的一部分,如下例所示。
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
"UpstreamPathTemplate": "/api/units/{subscriptionId}/{unitId}/updates",
"UpstreamHttpMethod": [
"Get"
],
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 50110
}
]
}
],
"GlobalConfiguration": {
}
}
在此示例中,Ocelot將使用上游路徑模板中{unitId}的值,並將其作為名為unitId的查詢字符串參數添加到下游請求中!
Ocelot還允許您將查詢字符串參數放在UpstreamPathTemplate中,以便您可以將某些查詢與某些服務匹配。
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/units/{subscriptionId}/{unitId}/updates",
"UpstreamPathTemplate": "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
"UpstreamHttpMethod": [
"Get"
],
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 50110
}
]
}
],
"GlobalConfiguration": {
}
}
在此示例中,Ocelot將僅匹配具有匹配的url路徑的請求,並且查詢字符串以unitId = something開頭。您可以在此之后進行其他查詢,但必須以匹配參數開頭。此外,Ocelot將交換查詢字符串中的{unitId}參數,並在下游請求路徑中使用它。
源碼地址
當然是放上實例中的源碼地址了:https://github.com/yilezhu/OcelotDemo
Ocelot簡易教程目錄
- Ocelot簡易教程(一)之Ocelot是什么
- Ocelot簡易教程(二)之快速開始1
- Ocelot簡易教程(二)之快速開始2
- Ocelot簡易教程(三)之主要特性及路由詳解
- Ocelot簡易教程(四)之請求聚合以及服務發現
- Ocelot簡易教程(五)之集成IdentityServer認證以及授權
- Ocelot簡易教程(六)之重寫配置文件存儲方式並優化響應數據
- Ocelot簡易教程(七)之配置文件數據庫存儲插件源碼解析
總結
本文主要是對Ocelot的新特性以及路由進行詳細的介紹,這些介紹對你使用ocelot會有很大的幫助。下篇文章呢,我會對請求聚合以及服務發現以及動態路由進行記錄,敬請期待!同時需要說明一點是,本文大部分內容是翻譯自官方文檔,當然中間穿插着自己在使用過程中一些理解,希望大家能夠喜歡!