KestrelServer詳解[1]:注冊監聽終結點(Endpoint)

具有跨平臺能力的KestrelServer是最重要的服務器類型。針對KestrelServer的設置均體現在KestrelServerOptions配置選項上,注冊的終結點是它承載的最重要的配置選項。這里所謂的終結點(Endpoint)與“路由”介紹的終結點不是一回事,這里表示的就是服務器在監聽請求時綁定的網絡地址,對應著一個System.Net.Endpoint對象。我們知道ASP.NET Core應用承載API也提供了注冊監聽地址的方法,其本質其實也是為了注冊終結點,那么兩種注冊方式如何取舍呢?[本文節選《ASP.NET Core 6框架揭秘》第18章]

一、UseKestrel擴展方法
二、兩種終結點的取舍
三、終結點配置
四、針對HTTPS的設置
五、限制約束
六、其他設置

一、UseKestrel擴展方法

IWebHostBuilder接口如下三個UseKestrel擴展方法重載會幫助我們完成KestrelServer的注冊并對KestrelServerOptions配置選項作相應設置,我們先來看看如何利用它們來注冊終結點。

public?static?class?WebHostBuilderKestrelExtensions
{public?static?IWebHostBuilder?UseKestrel(this?IWebHostBuilder?hostBuilder);public?static?IWebHostBuilder?UseKestrel(this?IWebHostBuilder?hostBuilder,Action<KestrelServerOptions>?options);public?static?IWebHostBuilder?UseKestrel(this?IWebHostBuilder?hostBuilder,?Action<WebHostBuilderContext,?KestrelServerOptions>?configureOptions);
}

注冊到KestrelServer上的終結點體現為如下這個Endpoint對象。Endpoint是對網絡地址的抽象,它們在大部分下體現為“IP地址+端口”或者“域名+端口”,對應的類型分別為IPEndPoint和DnsEndPoint。UnixDomainSocketEndPoint表示基于Unix Domain Socket/IPC Socket的終結點,它旨在實現同一臺機器上多個進程之間的通信(IPC)。FileHandleEndPoint表示指向某個文件句柄(比如TCP或者Pipe類型的文件句柄)的終結點。

public?abstract?class?EndPoint
{public?virtual?AddressFamily?AddressFamily?{?get;?}public?virtual?EndPoint?Create(SocketAddress?socketAddress);public?virtual?SocketAddress?Serialize();
}public?class?IPEndPoint?:?EndPoint
public?class?DnsEndPoint?:?EndPoint
public?sealed?class?UnixDomainSocketEndPoint?:?EndPoint
public?class?FileHandleEndPoint?:?EndPoint

終結點注冊利用如下這個ListenOptions配置選項來描述。該類型實現的IConnectionBuilder和IMultiplexedConnectionBuilder接口涉及針對連接的構建,我們將在后面討論這個話題。注冊的終結點體現為該配置選項的EndPoint屬性,如果是一個IPEndPoint對象,該對象也會體現在IPEndPoint屬性上。如果終結點類型為UnixDomainSocketEndPoint和FileHandleEndPoint,我們可以利用配置選項的SocketPath和FileHandle得到對應的Socket路徑和文件句柄。

public?class?ListenOptions?:?IConnectionBuilder,?IMultiplexedConnectionBuilder
{public?EndPoint?EndPoint?{?get;?}public?IPEndPoint?IPEndPoint?{?get;?}public?string?SocketPath?{?get;?}public?ulong?FileHandle?{?get;?}public?HttpProtocols?Protocols?{?get;?set;?}public?bool?DisableAltSvcHeader?{?get;?set;?}public?IServiceProvider?ApplicationServices?{?get;?}public?KestrelServerOptions?KestrelServerOptions?{?get;?}...
}

同一個終結點可以同時支持HTTP 1.x、HTTP 2 和HTTP 3三種協議,具體設置體現在Protocols屬性上,該屬性返回如下這個HttpProtocols枚舉。由于枚舉項Http3和Http1AndHttp2AndHttp3上面標注了RequiresPreviewFeaturesAttribute特性,如果需要采用HTTP 3協議,項目文件中必須添加“<EnablePreviewFeatures>true</EnablePreviewFeatures>”屬性。如果HTTP3終結點同時支持HTTP 1.X和HTTP 2,針對HTTP 1.X和HTTP 2的請求的響應一般會添加一個alt-svc (Alternative Service)報頭指示可以升級到HTTP 3,我們可以設置DisableAltSvcHeader屬性關閉此特性。該屬性默認值為Http1AndHttp2。

[Flags]
public?enum?HttpProtocols
{None?=?0,Http1?=?1,Http2?=?2,Http1AndHttp2?=?3,[RequiresPreviewFeatures]Http3?=?4,[RequiresPreviewFeatures]Http1AndHttp2AndHttp3?=?7
}

KestrelServerOptions的ListenOptions屬性返回的ListenOptions列表代表所有注冊的終結點,它由CodeBackedListenOptions和ConfigurationBackedListenOptions屬性合并而成,這兩個屬性分別表示通過代碼和配置注冊的終結點。基于“代碼”的終結點注冊由如下所示的一系列Listen和以“Listen”為前綴的方法來完成。除了這些注冊單個終結點的方法, ConfigureEndpointDefaults方法為注冊的所有終結點提供基礎設置。

public?class?KestrelServerOptions
{internal?List<ListenOptions>??CodeBackedListenOptions?{?get;?}internal?List<ListenOptions>??ConfigurationBackedListenOptions?{?get;?}internal?IEnumerable<ListenOptions>?????ListenOptions?{?get;?}public?void?Listen(EndPoint?endPoint);public?void?Listen(IPEndPoint?endPoint);public?void?Listen(EndPoint?endPoint,?Action<ListenOptions>?configure);public?void?Listen(IPAddress?address,?int?port);public?void?Listen(IPEndPoint?endPoint,?Action<ListenOptions>?configure);public?void?Listen(IPAddress?address,?int?port,?Action<ListenOptions>?configure);public?void?ListenAnyIP(int?port);public?void?ListenAnyIP(int?port,?Action<ListenOptions>?configure);public?void?ListenHandle(ulong?handle);public?void?ListenHandle(ulong?handle,?Action<ListenOptions>?configure);public?void?ListenLocalhost(int?port);public?void?ListenLocalhost(int?port,?Action<ListenOptions>?configure);public?void?ListenUnixSocket(string?socketPath);public?void?ListenUnixSocket(string?socketPath,?Action<ListenOptions>?configure);public?void?ConfigureEndpointDefaults(Action<ListenOptions>?configureOptions)...
}

二、兩種終結點的取舍

我們知道監聽地址不僅可以添加到WebApplication對象的Urls屬性中,WebApplication類型用來啟動應用的RunAsync和Run方法也提供了可缺省的參數url來指定監聽地址。從如下的代碼片段可以看出,這三種方式提供的監聽地址都被添加到了IServerAddressesFeature特性的Addresses屬性中。

public?sealed?class?WebApplication?:?IHost
{private?readonly?IHost?_host;public?ICollection<string>?Urls?=>?_host.Services.GetRequiredService<IServer>().Features.Get<IServerAddressesFeature>()?.Addresses????throw?new?InvalidOperationException("IServerAddressesFeature?could?not?be?found.");public?Task?RunAsync(string??url?=?null){Listen(url);return?((IHost)this).RunAsync();}public?void?Run(string??url?=?null){Listen(url);((IHost)this).Run();}private?void?Listen(string??url){if?(url?!=?null){var?addresses?=?ServerFeatures.Get<IServerAddressesFeature>()?.Addresses????throw?new?InvalidOperationException("No?valid?IServerAddressesFeature?is?found");addresses.Clear();addresses.Add(url);}}
}

如果KestrelServerOptions配置選項不能提供注冊的終結點,那么KestrelServer就會使用IServerAddressesFeature特性提供的地址來創建對應的終結點,否則就會根據它的PreferHostingUrls屬性來進行取舍。如果IServerAddressesFeature特性的PreferHostingUrls屬性返回True,它提供的地址會被選擇,否則就使用直接注冊到KestrelServerOptions配置選項的終結點。針對監聽地址的注冊和PreferHostingUrls的設置可以利用IWebHostBuilder接口如下兩個擴展方法來完成。從給出的代碼片段可以看出這兩個方法會將提供的設置存儲配置上,配置項名稱分別為“urls”和“preferHostingUrls”,對應著WebHostDefaults定義的兩個靜態只讀字段ServerUrlsKey和PreferHostingUrlsKey。既然這兩個設置來源于配置,我們自然可以利用命令行參數、環境變量或者直接修改對應配置項的方式來指定它們。

public?static?class?HostingAbstractionsWebHostBuilderExtensions
{public?static?IWebHostBuilder?UseUrls(this?IWebHostBuilder?hostBuilder,?params?string[]?urls)=>?hostBuilder.UseSetting(WebHostDefaults.ServerUrlsKey,?string.Join(';',?urls));public?static?IWebHostBuilder?PreferHostingUrls(this?IWebHostBuilder?hostBuilder,?bool?preferHostingUrls)=>?hostBuilder.UseSetting(WebHostDefaults.PreferHostingUrlsKey,?preferHostingUrls???"true"?:?"false");
}

如果服務器的特性集合提供的IServerAddressesFeature特性包含監聽地址,以配置方式設置的監聽地址和針對PreferHostingUrls的設置將會被忽略,這一個特性體現在GenericWebHostService的StartAsync方法中。如下面的代碼片段所示,該方法會從服務器中提取IServerAddressesFeature特性,只有該特性不能提供監聽地址的情況下,利用配置注冊的監聽地址和針對PreferHostingUrls的設置才會應用到該特性中。

internal?sealed?class?GenericWebHostService?:?IHostedService
{public?async?Task?StartAsync(CancellationToken?cancellationToken){...var?serverAddressesFeature?=?Server.Features.Get<IServerAddressesFeature>();var?addresses?=?serverAddressesFeature?.Addresses;if?(addresses?!=?null?&&?!addresses.IsReadOnly?&&?addresses.Count?==?0){var?text?=?Configuration[WebHostDefaults.ServerUrlsKey];if?(!string.IsNullOrEmpty(text)){serverAddressesFeature.PreferHostingUrls?=?WebHostUtilities.ParseBool(Configuration,?WebHostDefaults.PreferHostingUrlsKey);string[]?array?=?text.Split(';',?StringSplitOptions.RemoveEmptyEntries);foreach?(string?item?in?array){addresses.Add(item);}}}}
}

下面的演示程序通過調用IWebHostBuilder接口的UseKestrel擴展方法注冊了一個采用8000端口的本地終結點,通過調用UseUrls擴展方法注冊了一個采用9000端口的監聽地址。

var?builder?=?WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(kestrel?=>?kestrel.ListenLocalhost(8000)).UseUrls("http://localhost:9000");
var?app?=?builder.Build();
app.Run();

我們以命令行的方式兩次啟動了該程序。默認情況下應用會選擇調用UseKestrel擴展方法注冊的終結點。如果指定了命令行參數“preferHostingUrls=1”,那么最終使用的都是將是調用UseUrls擴展方法注冊的監聽地址。由于兩種情況都涉及到放棄某種設置,所以輸出了相應的日志。

e7a79c388f80f32bd2faccde8188718b.png
圖1 兩種終結點的選擇

三、終結點配置

KestrelServerOptions承載的很多設置都可以利用配置來提供。由于該配置選項類型的定義與配置的結構存在差異, KestrelServerOptions配置選項無法直接使用對應的IConfiguration對象進行綁定,所以KestrelServerOptions類型定義如下三個Configure方法。后面兩個方法提供了承載配置內容的IConfiguration對象,最后一個重載還提供了reloadOnChange參數來決定是否自動加載更新后的配置。第一個重載提供的其實是一個空的IConfiguration對象。

public?class?KestrelServerOptions
{public?KestrelConfigurationLoader?Configure();public?KestrelConfigurationLoader?Configure(IConfiguration?config);public?KestrelConfigurationLoader?Configure(IConfiguration?config,?bool?reloadOnChange)
}

三個Configure方法都返回KestrelConfigurationLoader對象,后者是對當前KestrelServerOptions配置選項和指定IConfiguration對象的封裝。KestrelConfigurationLoader的Load方法會讀取配置的內容并將其應用到KestrelServerOptions配置選項上,該類型還提供了一系列注冊各類終結點的方法。

public?class?KestrelConfigurationLoader
{public?KestrelServerOptions?Options?{?get;?}public?IConfiguration?Configuration?{?get;?}public?KestrelConfigurationLoader?Endpoint(string?name,?Action<EndpointConfiguration>?configureOptions);public?KestrelConfigurationLoader?Endpoint(IPAddress?address,?int?port);public?KestrelConfigurationLoader?Endpoint(IPAddress?address,?int?port,?Action<ListenOptions>?configure);public?KestrelConfigurationLoader?Endpoint(IPEndPoint?endPoint);public?KestrelConfigurationLoader?Endpoint(IPEndPoint?endPoint,?Action<ListenOptions>?configure);public?KestrelConfigurationLoader?LocalhostEndpoint(int?port);public?KestrelConfigurationLoader?LocalhostEndpoint(int?port,?Action<ListenOptions>?configure);public?KestrelConfigurationLoader?AnyIPEndpoint(int?port);public?KestrelConfigurationLoader?AnyIPEndpoint(int?port,?Action<ListenOptions>?configure);public?KestrelConfigurationLoader?UnixSocketEndpoint(string?socketPath);public?KestrelConfigurationLoader?UnixSocketEndpoint(string?socketPath,?Action<ListenOptions>?configure);public?KestrelConfigurationLoader?HandleEndpoint(ulong?handle);public?KestrelConfigurationLoader?HandleEndpoint(ulong?handle,?Action<ListenOptions>?configure);public?void?Load();
}

ASP.NET Core應用在啟動時會調用IHostBuilder接口如下這個ConfigureWebHostDefaults擴展方法進行初始化設置,該方法會從當前配置中提取出“Kestrel”配置節,并將其作為參數調用Configure方法將配置內容應用到KestrelServerOptions配置選項上。由于reloadOnChange參數被設置成了True,所以更新后的配置會自動被重新加載。

public?static?class?GenericHostBuilderExtensions
{public?static?IHostBuilder?ConfigureWebHostDefaults(this?IHostBuilder?builder,?Action<IWebHostBuilder>?configure)?=>?builder.ConfigureWebHost(webHostBuilder?=>?{WebHost.ConfigureWebDefaults(webHostBuilder);configure(webHostBuilder);});
}public?static?class?WebHost
{internal?static?void?ConfigureWebDefaults(IWebHostBuilder?builder){...builder.UseKestrel((builderContext,?options)?=>?options.Configure(builderContext.Configuration.GetSection("Kestrel"),?reloadOnChange:?true)...}
}

如下的代碼片段展現了針對終結點的配置。我們在“Kestrel:Endpoints”配置了兩個分別命名為“endpoint1”和“endpoint2”終結點,它們采用的監聽地址分別為“http://localhost:9000”和“https://localhost:9001”。KestrelServerOptions絕大部分配置選項都可以定義在配置文件中,具體的配置定義方法可以參閱官方文檔。

{"Kestrel":?{"Endpoints":?{"endpoint1":?{"Url":?"http://localhost:9000"},"endpoint2":?{"Url":?"https://localhost:9001"}}}
}

四、針對HTTPS的設置

較之普通的終結點,HTTPS(SSL/TLS)終結點需要提供額外的設置,這些設置大都體現在如下這個HttpsConnectionAdapterOptions配置選項上。KestrelServerOptions的ConfigureHttpsDefaults方法為所有HTTPS終結點提供了默認的設置。

public?class?HttpsConnectionAdapterOptions
{public?X509Certificate2??ServerCertificate?{?get;?set;?}public?Func<ConnectionContext?,?string?,?X509Certificate2?>??ServerCertificateSelector?{?get;?set;?}public?TimeSpan?HandshakeTimeout?{?get;?set;?}public?SslProtocols?SslProtocols?{?get;?set;?}public?Action<ConnectionContext,?SslServerAuthenticationOptions>??OnAuthenticate?{?get;?set;?}public?ClientCertificateMode?ClientCertificateMode?{?get;?set;?}public?Func<X509Certificate2,?X509Chain?,?SslPolicyErrors,?bool>??ClientCertificateValidation?{?get;?set;?}public?bool?CheckCertificateRevocation?{?get;?set;?}public?void?AllowAnyClientCertificate()?{?get;?set;?}
}public?static?class?KestrelServerOptions
{public?void?ConfigureHttpsDefaults(Action<HttpsConnectionAdapterOptions>?configureOptions);...
}

表示服務端證書的X509Certificate2對象可以直接設置到ServerCertificate屬性上,我們也可以在ServerCertificateSelector屬性上設置一個根據當前連結動態選擇證書的委托。SslProtocols屬性用來設置采用的協議(SSL或者TLS),對應的類型為如下這個SslProtocols枚舉。HandshakeTimeout屬性用來設置TLS/SSL“握手”的超時時間,默認為10秒。

[Flags]
public?enum?SslProtocols
{None?=?0x0,[Obsolete("SslProtocols.Ssl2?has?been?deprecated?and?is?not?supported.")]Ssl2?=?0xC,[Obsolete("SslProtocols.Ssl3?has?been?deprecated?and?is?not?supported.")]Ssl3?=?0x30,Tls?=?0xC0,[Obsolete("SslProtocols.Default?has?been?deprecated?and?is?not?supported.")]Default?=?0xF0,Tls11?=?0x300,Tls12?=?0xC00,Tls13?=?0x3000
}

HTTPS主要解決的是服務端的認證和傳輸安全問題,所以服務端的認證信息需要在前期“協商”階段利用建立的安全通道傳遞給客戶端,具體的認證信息是如下這個SslServerAuthenticationOptions配置選項格式化后的結果。HttpsConnectionAdapterOptions的OnAuthenticate屬性提供的委托可以幫助我們對這個配置選項進行設置,所以絕大部分HTTPS相關的設置都可以利用該屬性來完成。

public?class?SslServerAuthenticationOptions
{public?bool?AllowRenegotiation?{?get;?set;?}public?bool?ClientCertificateRequired?{?get;?set;?}public?List<SslApplicationProtocol>??ApplicationProtocols?{?get;?set;?}public?RemoteCertificateValidationCallback??RemoteCertificateValidationCallback?{?get;?set;?}public?ServerCertificateSelectionCallback??ServerCertificateSelectionCallback?{?get;?set;?}public?X509Certificate??ServerCertificate?{?get;?set;?}public?SslStreamCertificateContext??ServerCertificateContext?{?get;?set;?}public?SslProtocols?EnabledSslProtocols?{?get;?set;?}public?X509RevocationMode?CertificateRevocationCheckMode?{?get;?set;?}public?EncryptionPolicy?EncryptionPolicy?{?get;?set;?}public?CipherSuitesPolicy??CipherSuitesPolicy?{?get;?set;?}
}

HTTPS不僅僅能夠幫助客戶端來驗證服務端的身份,還能幫助服務端來對客戶端身份進行驗證。服務端驗證利用服務端證書來完成,與之類似,服務端要識別客戶端的身份,同樣需要客戶端提供證書。我們可以利用HttpsConnectionAdapterOptions的ClientCertificateMode屬性來決定是否要求客戶端提供證書,該屬性類型為如下這個ClientCertificateMode枚舉。針對客戶端認證的驗證可以利用ClientCertificateValidation屬性設置的委托來完成。

public?enum?ClientCertificateMode
{NoCertificate,AllowCertificate,RequireCertificate,DelayCertificate
}

由權威機構(Certificate Authority)頒發的證書可能會由于某種原因被撤銷,我們有兩種途徑來確定某張證書是否處于被撤銷的狀態:證書頒發機構可以采用標準的OCSP(Online Certificate Status Protocol)協議提供用于確定證書狀態的API,也可以直接提供一份撤銷的證書清單(CRL:Certificate Revocation List)。HttpsConnectionAdapterOptions的CheckCertificateRevocation屬性用來決定是否需要對證書的撤銷狀態進行驗證。如果不需要對客戶端證書作任何驗證,我們可以調用HttpsConnectionAdapterOptions的AllowAnyClientCertificate方法。

當我們將某個終結點注冊到KestrelServer上并生成對應ListenOptions配置選項后,我們可以調用后者的UseHttps擴展方法(注冊終結點的很多方法都提供一個Action<ListenOptions>參數)完成針對HTTPS的設置,我們有如下這一系列UseHttps重載可供選擇。對于證書的設置,我們可以直接指定一個X509Certificate2對象,也可以指定證書文件的路徑(一般還需要提供讀取證書的密碼),還可以指定證書的存儲(Certificate Store)。我們可以利用部分方法重載提供的委托對HttpsConnectionAdapterOptions配置選項進行設置。部分方法重載還提供了一個ServerOptionsSelectionCallback委托直接返回SslServerAuthenticationOptions配置選項。

public?static?class?ListenOptionsHttpsExtensions
{public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?string?fileName);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?string?fileName,?string??password);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?string?fileName,?string??password,?Action<HttpsConnectionAdapterOptions>?configureOptions);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?StoreName?storeName,?string?subject);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?StoreName?storeName,?string?subject,?bool?allowInvalid);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?StoreName?storeName,?string?subject,?bool?allowInvalid,?StoreLocation?location);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?StoreName?storeName,?string?subject,?bool?allowInvalid,?StoreLocation?location,?Action<HttpsConnectionAdapterOptions>?configureOptions);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?X509Certificate2?serverCertificate);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?X509Certificate2?serverCertificate,?Action<HttpsConnectionAdapterOptions>?configureOptions);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?Action<HttpsConnectionAdapterOptions>?configureOptions);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?HttpsConnectionAdapterOptions?httpsOptions);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?ServerOptionsSelectionCallback?serverOptionsSelectionCallback,?object?state);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?ServerOptionsSelectionCallback?serverOptionsSelectionCallback,?object?state,?TimeSpan?handshakeTimeout);public?static?ListenOptions?UseHttps(this?ListenOptions?listenOptions,?TlsHandshakeCallbackOptions?callbackOptions);
}public?delegate?ValueTask<SslServerAuthenticationOptions>?ServerOptionsSelectionCallback(SslStream?stream,?SslClientHelloInfo?clientHelloInfo,?object??state,?CancellationToken?cancellationToken);

除了調用上述這些方法來為注冊的終結點提供HTTPS相關的設置外,這些設置也可以按照如下的方式放在終結點的配置中。

{"Kestrel":?{"Endpoints":?{"MyHttpsEndpoint":?{"Url":?"https://localhost:5001","ClientCertificateMode":?"AllowCertificate","Certificate":?{"Path":?"c:\\certificates\\foobar.pfx>","Password":?"password"}}}}
}

五、限制約束

為了確保KestrelServer穩定可靠地運行,需要根據需要為它設置相應的限制和約束,這些設置體現在KestrelServerOptions配置選項Limits屬性返回的KestrelServerLimits對象上。

public?class?KestrelServerOptions
{public?KestrelServerLimits?Limits?{?get;?}?=?new?KestrelServerLimits();
}public?class?KestrelServerLimits
{public?long??MaxConcurrentConnections?{?get;?set;?}public?long??MaxConcurrentUpgradedConnections?{?get;?set;?}public?TimeSpan?KeepAliveTimeout?{?get;?set;?}public?int?MaxRequestHeaderCount?{?get;?set;?}public?long??MaxRequestBufferSize?{?get;?set;?}public?int?MaxRequestHeadersTotalSize?{?get;?set;?}public?int?MaxRequestLineSize?{?get;?set;?}public?long??MaxRequestBodySize?{?get;?set;?}public?TimeSpan?RequestHeadersTimeout?{?get;?set;?}public?MinDataRate?MinRequestBodyDataRate?{?get;?set;?}public?long??MaxResponseBufferSize?{?get;?set;?}public?MinDataRate?MinResponseDataRate?{?get;?set;?}public?Http2Limits?Http2?{?get;?}public?Http3Limits?Http3?{?get;?}
}

KestrelServerLimits利用其豐富的屬性對連接、請求和響應進行了相應的限制。KestrelServer提供了針對HTTP 2和HTTP3的支持,針對性的限制設置體現在KestrelServerLimits類型的Http2和Http3屬性上。下表對定義在KestrelServerLimits類型中的這些屬性所體現的限制約束進行了簡單說明。

屬性

含  義

MaxConcurrentConnections

最大并發連接。如果設置為Null(默認值),意味著不作限制。

MaxConcurrentUpgradedConnections

可升級連接(比如從HTTP升級到WebSocket)的最大并發數。如果設置為Null(默認值),意味著不作限制。

KeepAliveTimeout

連接保持活動狀態的超時時間,默認值為130秒。

MaxRequestHeaderCount

請求攜帶的最大報頭數量,默認值為100。

MaxRequestBufferSize

請求緩沖區最大容量,默認值為1,048,576字節(1M)。

MaxRequestHeadersTotalSize

請求攜帶報頭總字節數,默認值為 32,768字節(32K)。

MaxRequestLineSize

對于HTTP 1.X來說就是請求的首行(Request Line)最大字節數。對于HTTP 2/3來說就是 :method, :scheme, :authority, and :path這些報頭的總字節數。默認值為8,192 字節(8K)。

MaxRequestBodySize

請求主體最大字節數,默認值為30,000,000 字節(約28.6M)。如果設置為Null,意味著不作限制。

RequestHeadersTimeout

接收請求報頭的超時時間,默認為30秒。

MinRequestBodyDataRate

請求主體內容最低傳輸率。

MaxResponseBufferSize

響應緩沖區最大容量,默認值為65,536(1M)。

MinResponseDataRate

響應最低傳輸率。

KestrelServerLimits的MinRequestBodyDataRate和MinResponseDataRate屬性返回的最低傳輸率體現為如下這個MinDataRate對象。如果沒有達到設定的傳輸率,當前連接就會被重置。MinDataRate對象除了提供表示傳輸率的BytesPerSecond屬性外,還提供了一個表示“寬限時間”的GracePeriod屬性。并非傳輸率下降到設定的閾值的那一刻就重置連接,只要在指定的時段內傳輸率上升到閾值以上也沒有問題。MinRequestBodyDataRate和MinResponseDataRate屬性的默認值均為“240 bytes/second(5 seconds)”。

public?class?MinDataRate
{public?double?BytesPerSecond?{?get;?}public?TimeSpan?GracePeriod?{?get;?}public?MinDataRate(double?bytesPerSecond,?TimeSpan?gracePeriod);
}

HTTP 1.X建立在TCP之上,客戶端和服務端之間的交互依賴預先創建的TCP連接。雖然HTTP 1.1引入的流水線技術允許客戶端可以隨時向服務端發送請求,而無需等待接收到上一個請求的響應,但是響應依然只能按照請求的接收順序返回的。真正意義上的“并發”請求只能利用多個連接來完成,但是針對同一個域名支持的TCP連接的數量又是有限的。這個問題在HTTP 2得到了一定程度的解決。

與采用文本編碼的HTTP 1.X相比, HTTP 2采用更加高效的二進制編碼。幀(Frame)成為了基本通信單元,單個請求和響應可以分解成多個幀進行發送。客戶端和服務端之間額消息交換在一個支持雙向通信的信道(Channel)中完成,該信道被稱為“流(Stream)”。每一個流具有一個唯一標識,同一個TCP連接可以承載成百上千的流。每個幀攜帶著所屬流的標識,所以它可以隨時被“亂序”發送,接收端可以利用流的標識進行重組,所以HTTP 2在同一個TCP連接上實現了“多路復用”。

使用同一個連接發送的請求和響應都存在很多重復的報頭,為了減少報頭內容占據的帶寬,HTTP 2會采用一種名為HPACK的壓縮算法對報頭文本進行編碼。HPACK會在發送和接收端維護一個索引表來存儲編碼的文本,報頭內容在發送前會被替換成在該表的索引,接收端這利用此索引在本地壓縮表中找到原始的內容。

public?class?Http2Limits
{public?int?????MaxStreamsPerConnection?{?get;?set;?}public?int?????HeaderTableSize?{?get;?set;?}public?int?????MaxFrameSize?{?get;?set;?}public?int?????MaxRequestHeaderFieldSize?{?get;?set;?}public?int?????InitialConnectionWindowSize?{?get;?set;?}public?int?????InitialStreamWindowSize?{?get;?set;?}public?TimeSpan?????KeepAlivePingDelay?{?get;?set;?}public?TimeSpan?????KeepAlivePingTimeout?{?get;?set;?}
}

于HTTP 2相關限制和約束的設置體現在KestrelServerLimits的Http2屬性上,該屬性返回如上所示的Http2Limits對象。下表對定義在Http2Limits類型中的這些屬性所體現的限制約束進行了簡單說明。

屬性

含  義

MaxStreamsPerConnection

連接能夠承載的流數量,默認值為100。

HeaderTableSize

HPACK報頭壓縮表的容量,默認值為4096。

MaxFrameSize

幀的最大字節數,有效值在[214~224?– 1]區間范圍內,默認值為214(16384)。

MaxRequestHeaderFieldSize

最大請求報頭(含報頭名稱)的最大字節數,默認值為214(16384)。

InitialConnectionWindowSize

連接的初始化請求主體緩存區的大小,有效值在[65535~231]區間范圍內,默認為131072。

InitialStreamWindowSize

流的初始化請求主體緩存區的大小,有效值在[65535~231]區間范圍內,默認為98304。

KeepAlivePingDelay

如果服務端在該屬性設定的時間跨度內沒有接收到來自客戶端的有效幀,它會主動發送Ping請求確定客戶端的是否保持活動狀態,默認值為1秒。

KeepAlivePingTimeout

發送Ping請求的超時時間,如果客戶端在該時限內一直處于為活動狀態,當前連接將被關閉,默認值為20秒。

由于HTTP 2的多路復用是在同一個TCP連接上實現的,這樣的實現并不“純粹”,因為它不可能解決由于TCP的“擁塞控制”機制導致的“隊頭阻塞(Header-Of-Line Blocking)”問題。如果希望在得到并發支持的前提下還能在低延時上有更好的作為,就不得不拋棄TCP。目前被正式確定為HTTP 3的QUIC(Quick UDP Internet Connection)就將TCP替換成了UDP。如果KestrelServer支持HTTP 3,我們可以利用KestrelServerLimits的Http3屬性返回的Http3Limits對象都限制約束進行針對性設置。Http3Limits只包含如下這個表示最大請求報頭字節數的MaxRequestHeaderFieldSize屬性,它的默認值為16384。

public?class?Http3Limits
{public?int?MaxRequestHeaderFieldSize?{?get;?set;}
}

六、其他設置

除了注冊的終結點和基于通信的限制約束,KestrelServerOptions配置選項還利用如下的屬性承載著其他的設置。

public?class?KestrelServerOptions
{public?bool?AddServerHeader?{?get;?set;?}public?bool?AllowResponseHeaderCompression?{?get;?set;?}public?bool?AllowSynchronousIO?{?get;?set;?}public?bool?AllowAlternateSchemes?{?get;?set;?}public?bool?DisableStringReuse?{?get;?set;?}public?Func<string,?Encoding>?RequestHeaderEncodingSelector?{?get;?set;?}public?Func<string,?Encoding>?ResponseHeaderEncodingSelector?{?get;?set;?}
}

下表對定義在KestrelServerOptions類型中的上述這些屬性進行了簡單的說明。

屬性

含  義

AddServerHeader

是否會在回復的響應中自動添加“Server: Kestrel”報頭,默認值為True。

AllowResponseHeaderCompression

是否允許對響應報頭進行HPACK壓縮,默認值為True。

AllowSynchronousIO

是否允許對請求和響應進行同步IO操作,默認值為False,意味這個默認情況下以同步方式讀取請求和寫入響應都會拋出異常。

AllowAlternateSchemes

是否允許為“:scheme”字段(針對HTTP 2和HTTP 3)提供一個與當前傳輸不匹配的值(“http”或者“https”),默認值為False。如果將這個屬性設置為True,意味著HttpRequest.Scheme屬性可能與采用的傳輸類型不匹配。

DisableStringReuse

創建的字符串是否可以在多個請求中復用。

RequestHeaderEncodingSelector

用于設置某個請求報頭采用的編碼方式,默認為Utf8Encoding。

ResponseHeaderEncodingSelector

用于設置某個響應報頭采用的編碼方式,默認為ASCIIEncoding。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282570.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282570.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282570.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php截取字符串,帶中文,多余的省略號代替

function subtext($text, $length) {if(mb_strlen($text, utf8) > $length) {return mb_substr($text, 0, $length, utf8)....;} else {return $text;}}$str 我們是family happy family; echo subtext($str,5); //我們是fa...

數據庫添加

<body><form action"herozhuce.php" method"post"> <div>賬號<input type"text" name"account"/></div> <div>密碼<input type"text" name"password"/></div> &…

快來加入阿里云大學【云學院】班級助理招募—機會稍縱即逝,錯過遙遙無期!...

2019獨角獸企業重金招聘Python工程師標準>>> 如果你對云計算、大數據、云安全、人工智能領域感興趣~ 如果你想從事與此相關的工作~~ 如果你又喜歡邊交流邊學習的方式~ 那么&#xff0c;加入我們吧&#xff01; 我們將為你提供一個廣闊的平臺&#xff0c;讓你接觸到云…

深入理解ajax系列第五篇——進度事件

前面的話 一般地&#xff0c;使用readystatechange事件探測HTTP請求的完成。XHR2規范草案定義了進度事件Progress Events規范&#xff0c;XMLHttpRequest對象在請求的不同階段觸發不同類型的事件&#xff0c;所以它不再需要檢査readyState屬性。這個草案定義了與客戶端服務器通…

對象(poco)深度克隆

提供深度克隆對象功能,基于編譯表達式實現&#xff0c;性能與原生代碼幾無差別&#xff0c;遠超 json/binary 序列化實現。1. 簡單示例class Person {public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }public DateTime Birth { get; s…

php將數字轉化為中文大寫人民幣格式

<?phpfunction cny($ns) {static $cnums array("零","壹","貳","叁","肆","伍","陸","柒","捌","玖"),$cnyunits array("圓","角","分&…

BZOJ1787 [Ahoi2008]Meet 緊急集合 LCA

歡迎訪問~原文出處——博客園-zhouzhendong 去博客園看該題解 題目傳送門 - BZOJ1787 題意概括 有一棵節點為n個(n≤500000)的樹。接下來m次詢問(m≤500000)&#xff0c;每次給出3個點 a,b,c &#xff0c;現在讓你求一個點 p &#xff0c;使得 dis(p,a) dis(p,b) dis(p,c) 最…

Linux之ACL權限控制

ACL權限控制主要目的是提供傳統的owner,group,other的read,wirte,execute權限之外的具體權限設置&#xff0c;可以針對單一用戶或組來設置特定的權限 設置ACL權限&#xff1a;setfacl查看ACL權限&#xff1a;getfacl 比如&#xff1a;某一目錄權限為 drwx------ 2 root root 40…

WIX、Squarespace、WordPress 三者的優劣分別是什么?

層出不窮的智能建站&#xff0c;模板建站&#xff0c;源碼建站&#xff0c;云建站&#xff0c;仿站&#xff0c;各種建站概念都拋灑于紅海之中。到底什么樣的網站適合自己&#xff0c;什么樣的網站值得我們去消費&#xff0c;什么樣的網站能長久&#xff0c;是個非常值得思考的…

平滑的加權輪詢均衡算法

前言在反向代理、路由、分布式應用調度等場景中通常都需要用到負載均衡算法&#xff0c;負載均衡的關鍵要點是“均衡”&#xff0c;即確保調用請求能均衡地落到多個處理節點上&#xff0c;負載均衡算法一般使用隨機或輪詢都可以保證均衡性。現實中由于服務器性能或資源分配的差…

php類精確驗證身份證號碼

<?php class check_IdCard {// $num為身份證號碼&#xff0c;$checkSex&#xff1a;1為男&#xff0c;2為女&#xff0c;不輸入為不驗證public function checkIdentity($num, $checkSex ) { // 不是15位或不是18位都是無效身份證號if (strlen($num) ! 15 && strl…

請說說接口和抽象類的區別?

1.從使用目的來看&#xff1a; 接口只是一個類間的協議&#xff0c;它并沒有規定怎么去實現&#xff1b; 抽象類可以重用你代碼使你的代碼更加簡潔&#xff1b;2.從行為來看&#xff1a; 接口可以多繼承,multi-implement 抽象類不能實例化&#xff0c;必須子類化才能實例化…

GitHub 使用

Git 是由 Linux 之父 Linus Tovalds 為了更好的管理 linux 內核開發而創立的分布是版本控制/軟件管理配置軟件. 簡單來說, Git 管理你的 代碼的歷史記錄 的工具. 首先注冊賬戶 (已經完成, moveofgod) 然后, 下載一個 GitHub Desktop(mac), msisgit 客戶端 (可以用命令行實現, …

LinkedHashMap 與 HashMap區別

2019獨角獸企業重金招聘Python工程師標準>>> LinkedHashMap 與 HashMap區別 &#xff08;非原創&#xff09; HashMap,LinkedHashMap,TreeMap都屬于Map Map 主要用于存儲鍵(key)值(value)對&#xff0c;根據鍵得到值&#xff0c;因此鍵不允許鍵重復,但允許值重復。 …

C# 11 中的 file local type

C# 11 中的 file local typeIntro在之前的版本中&#xff0c;我們想要一個類型只在當前的類型中生效&#xff0c;通常我們會在一個類的內部聲明一個 private 的類型以此來控制這個類型的訪問權限&#xff0c;在 C# 11 中引入了一個 file local type&#xff0c;僅在聲明類型的這…

PHP實現類似百度搜索自動完成(代碼簡單)

一、效果圖: 二、HTML代碼 <html lang"en"> <head><meta charset"utf-8"><title>jQuery UI 自動完成&#xff08;Autocomplete&#xff09; - 默認功能</title><link rel"stylesheet" href"/public/Auto…

Mysql讀寫分離php腳本

<?php/*php如何連接mysql*/ /*$link mysql_connect(‘localhost‘, ‘root‘, ‘‘);if (!$link) {die(‘Could not connect: ‘ . mysql_error());}echo ‘Connected successfully‘;mysql_close($link);*/ /*php如何選擇數據庫*//*$link mysql_connect(‘localhost‘, …

CentOS 搭建Postfix+Dovecot簡單郵件系統

2019獨角獸企業重金招聘Python工程師標準>>> 服務器信息 系統&#xff1a;CentOS 6.5 minimal版本 主機&#xff1a;虛擬機 虛擬機IP&#xff1a;192.168.128.128/24 宿主IP:10.1.79.24/24 安裝postfix 注意&#xff1a;CentOS 7實際上已經用postfixSasl2代替sendma…

Js獲取當前頁面URL各種參數

JS獲取當前頁面URL各種參數 一&#xff1a;Location Location 對象包含有關當前 URL 的信息。 Location 對象是 Window 對象的一個部分&#xff0c;可通過 window.location 屬性來訪問。 hash設置或返回從井號 (#) 開始的 URL&#xff08;錨&#xff09;。host設置或返回主機名…

php面試題2018

一 、PHP基礎部分 1、PHP語言的一大優勢是跨平臺&#xff0c;什么是跨平臺&#xff1f; PHP的運行環境最優搭配為ApacheMySQLPHP&#xff0c;此運行環境可以在不同操作系統&#xff08;例如windows、Linux等&#xff09;上配置&#xff0c;不受操作系統的限制&#xff0c;所以…