ASP.NET Core的Kestrel伺服器(轉載)
Kestrel是一個基於libuv的跨平臺ASP.NET Core web伺服器,libuv是一個跨平臺的非同步I/O庫。ASP.NET Core模板專案使用Kestrel作為預設的web伺服器。
Kestrel支援以下功能:
- HTTPS
- 用於啟用不透明升級的WebSockets
- 位於Nginx之後的高效能Unix sockets
Kestrel 被.NET Core支援的所有平臺和版本所支援
何時使用Kestrel和反向代理伺服器
如果你的應用只接收來自內部網路的請求,你可以只使用Kestrel本身。
如果你將你的應用部署在公共網路上,我們建議你使用IIS,Nginx或者Apache作為反向代理伺服器。一個反向代理伺服器接收來自網路的HTTP請求並且在經過一些初步處理後將請求傳遞到Kestrel伺服器。
出於安全性的理由,反向代理常常被edge deployments所採用。因為Kestrel相對較新,對抵禦安全攻擊至今還沒有一個完整的功能補充。安全性處理包括但不限於適當的超時,大小的限制,以及併發連線限制等問題。
另一個需要反向代理的場景是,你有多個需要在單獨的伺服器上執行並分享同一埠的應用。因為Kestrel不支援在多程序間分享同一埠,所以應用並不能直接和Kestrel合作。當你在某個埠上配置Kestrel執行偵聽時,不算主機頭如何標識,Kestrel會為該埠處理所有的流量。反向代理可以為多個應用共享唯一埠並將流量傳送給Kestrel。
即使不需要反向代理伺服器,使用它也可以簡化負載均衡和SSL設定 -- 只要你的反向代理伺服器需要SSL證書,並且該伺服器可以和你的應用在內部網中通過普通HTTP進行通訊。
託管模型
程序內託管模型
使用程序內託管,ASP.NET Core 在與其 IIS 工作程序相同的程序中執行。 這樣可消除通過環回介面卡代理請求時的程序外效能損失,環回介面卡是一個網路介面,用於將傳出的網路流量返回給同一計算機。 IIS 使用 Windows 程序啟用服務 (WAS) 處理程序管理。
ASP.NET Core 模組:
- 執行應用初始化。
- 載入 CoreCLR。
- 呼叫 Program.Main。
- 處理 IIS 本機請求的生存期。
下圖說明了 IIS、ASP.NET Core 模組和程序內託管的應用之間的關係:
請求從 Web 到達核心模式 HTTP.sys 驅動程式。 驅動程式將本機請求路由到網站的配置埠上的 IIS,通常為 80 (HTTP) 或 443 (HTTPS)。 該模組接收本機請求,並將它傳遞給 IIS HTTP 伺服器 (IISHttpServer)。 IIS HTTP 伺服器是將請求從本機轉換為託管的 IIS 程序內伺服器實現。
IIS HTTP 伺服器處理請求之後,請求會被推送到 ASP.NET Core 中介軟體管道中。 中介軟體管道處理該請求並將其作為 HttpContext 例項傳遞給應用的邏輯。 應用的響應傳遞迴 IIS,IIS 將響應推送回發起請求的客戶端。
程序內託管選擇使用現有應用,但 dotnet new 模板預設使用所有 IIS 和 IIS Express 方案的程序內託管模型。
程序外託管模型
由於 ASP.NET Core 應用在獨立於 IIS 工作程序的程序中執行,因此該模組會處理程序管理。 該模組在第一個請求到達時啟動 ASP.NET Core 應用的程序,並在應用關閉或崩潰時重新啟動該應用。 這基本上與在 Windows 程序啟用服務 (WAS) 託管的程序內執行的應用中出現的行為相同。
下圖說明了 IIS、ASP.NET Core 模組和程序外託管的應用之間的關係:
請求從 Web 到達核心模式 HTTP.sys 驅動程式。 驅動程式將請求路由到網站的配置埠上的 IIS,通常為 80 (HTTP) 或 443 (HTTPS)。 該模組將該請求轉發到應用的隨機埠(非埠 80/443)上的 Kestrel。
該模組在啟動時通過環境變數指定埠,IIS 整合中介軟體將伺服器配置為偵聽 http://localhost:{PORT}。 執行其他檢查,拒絕不是來自該模組的請求。 該模組不支援 HTTPS 轉發,因此即使請求由 IIS 通過 HTTPS 接收,它們還是通過 HTTP 轉發。
Kestrel 從模組獲取請求後,請求會被推送到 ASP.NET Core 中介軟體管道中。 中介軟體管道處理該請求並將其作為 HttpContext 例項傳遞給應用的邏輯。 IIS 整合新增的中介軟體會將方案、遠端 IP 和 pathbase 更新到帳戶以將請求轉發到 Kestrel。 應用的響應傳遞迴 IIS,IIS 將響應推送回發起請求的 HTTP 客戶端。
有關 IIS 和 ASP.NET Core 模組的配置指南,請參閱以下主題:
如何在ASP.NET Core應用中使用Kestrel
安裝 Microsoft.AspNetCore.Server.Kestrel Nuget包。
在應用的Main方法中呼叫WebHostBuilder的UseKestrel 擴充套件方法,指定你需要的Kestrel選項,如以下示例所示:
public static int Main(string[] args) { Console.WriteLine("Running demo with Kestrel."); var config = new ConfigurationBuilder() .AddCommandLine(args) .Build(); var builder = new WebHostBuilder() .UseContentRoot(Directory.GetCurrentDirectory()) .UseConfiguration(config) .UseStartup<Startup>() .UseKestrel(options => { if (config["threadCount"] != null) { options.ThreadCount = int.Parse(config["threadCount"]); } }) .UseUrls("http://localhost:5000"); var host = builder.Build(); host.Run(); return 0; }
URL 字首
預設情況下,ASP.NET Core專案綁定了http://localhost:5000。通過使用UseUrls擴充套件方法——編輯urls命令列引數,或者是通過ASP.NET Core配置系統,你可以為Ketrel配置URL字首和埠號以用來偵聽請求。關於這些方法更多的資訊,請參考Hosting。有關於當你使用IIS作為反向代理時,URL繫結是如何工作的資訊,請參考ASP.NET Core 模組。
Kestrel URL字首可以是以下格式中的任一種。
- IPv4 地址和埠號
http://65.55.39.10:80/ https://65.55.39.10:443/
- IPv6 地址和埠號
http://[0:0:0:0:0:ffff:4137:270a]:80/ https://[0:0:0:0:0:ffff:4137:270a]:443/
IPv6中的 [::] 等價於 IPv4 0.0.0.0。
- 主機名和埠號
http://contoso.com:80/ http://*:80/ https://contoso.com:443/ https://*:443/
主機名稱,*,以及+,都不是特殊的。任何沒有公認的IP 或是“localhost”的地址將繫結到所有的IPv4和IPv6的IP上。如果你需要為不同的ASP.NET Core應用在同一埠上繫結不同的主機名,請使用WebListener或者諸如IIS,Nginx或Apache這樣的反向代理伺服器。
* "Localhost" 名稱和埠號或回送IP地址和埠號
http://localhost:5000/ http://127.0.0.1:5000/ http://[::1]:5000/
當localhost被指定時,Kestrel會嘗試去繫結到IPv4和IPv6的環回介面。如果被請求的埠號正在任一環回介面上被其他服務所使用,Kestrel將會啟動失敗。如果任一環回接口出於各種原因而不可用(最通常的情況是因為IPv6暫不被支援),Kestrel將記錄下一個警告資訊。
- Unix socket
http://unix:/run/dan-live.sock
如果你指定了埠號0,Kestrel將動態地繫結到合適的埠號。除了localhost名稱,繫結到0埠號被其他任何主機名稱或IP地址所允許。
當你指定了埠號0,你可以使用IServerAddressesFeature介面去決定執行時Kestrel實際繫結到哪個埠。下列示例用於獲取繫結埠並且在console上顯示出來。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); var serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>(); app.UseStaticFiles(); app.Run(async (context) => { context.Response.ContentType = "text/html"; await context.Response .WriteAsync("<p>Hosted by Kestrel</p>"); if (serverAddressesFeature != null) { await context.Response .WriteAsync("<p>Listening on the following addresses: " + string.Join(", ", serverAddressesFeature.Addresses) + "</p>"); } await context.Response.WriteAsync($"<p>Request URL: {context.Request.GetDisplayUrl()}<p>"); }); }
SSL的URL字首
如果你呼叫UseSSL擴充套件方法,請確保在https:中包含URL字首,如下所示:
var host = new WebHostBuilder() .UseKestrel(options => { options.UseHttps("testCert.pfx", "testPassword"); }) .UseUrls("http://localhost:5000", "https://localhost:5001") .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup<Startup>() .Build();
Note
HTTPS和HTTP不能在同一埠上被託管。
Feature Comparison for Kestrel vs IIS
Here is an IIS vs Kestrel comparison of some key features. This should help you better understand the limitations of Kestrel. You can overcome these limitations by pairing it up with IIS or NGINX.
IIS | Kestrel | |
Platform Support | Windows | Windows/Linux/Mac |
Static Files | Yes | Yes |
HTTP Access Logs | Yes | No |
Port Sharing / Multiple apps* | Yes | No |
SSL Certificates | Yes | Internal** |
Windows Authentication | Yes | No |
Management Console | Yes | No |
Process Activation (start it up) | Yes | No |
Application Initialization (warm it up) | Yes | No |
Configuration API | Yes | No |
Request Filtering & Limits | Yes | No |
IP & Domain Restrictions | Yes | No |
HTTP Redirect Rules | Yes | No |
WebSocket Protocol | Yes | Middleware |
Response Output Caching | Yes | No |
Compression | Optional | Optional |
FTP Server | Yes | No |
本教程在本地僅使用Kestrel,在將該應用部署到Azure之後,它將在Windows上使用IIS作為反向代理伺服器。
參考文獻:
- Kestrel source code
- Web server implementations in ASP.NET Core
- Kestrel web server implementation in ASP.NET Core
- ASP.NET Core Web Servers: Kestrel vs IIS Feature Comparison and Why You Need Both