ASP.NET Core 中的 HTTP.sys Web 服务器实现
HTTP.sys
是仅在 Windows 上运行的适用于 ASP.NET Core 的 Web 服务器
。 HTTP.sys
是 Kestrel
服务器的替代选择,提供了一些 Kestrel
不提供的功能。
重要
HTTP.sys 与ASP.NET Core 模块
不兼容,无法与 IIS 或 IIS Express 结合使用。
HTTP.sys 支持以下功能:
Windows 身份验证
- 端口共享
- 具有 SNI 的 HTTPS
- 基于 TLS 的 HTTP/2(Windows 10 或更高版本)
- 直接文件传输
- 响应缓存
WebSocket
(Windows 8 或更高版本)
受支持的 Windows 版本:
- Windows 7 或更高版本
- Windows Server 2008 R2 或更高版本
何时使用 HTTP.sys
HTTP.sys
对于以下情形的部署来说很有用:
-
需要将服务器直接公开到 Internet 而不使用 IIS 的部署。
-
内部部署需要 Kestrel 中没有的功能,如
Windows 身份验证
。
HTTP.sys
是一项成熟的技术,可以抵御多种攻击,并提供可靠、安全、可伸缩的全功能 Web 服务器。 IIS 本身作为 HTTP.sys 之上的 HTTP 侦听器运行。
HTTP/2 支持
如果满足以下基本要求,将为 ASP.NET Core 应用启用 HTTP/2:
- Windows Server 2016/Windows 10 或更高版本
- 应用程序层协议协商 (ALPN) 连接
- TLS 1.2 或更高版本的连接
如果已建立 HTTP/2
连接,HttpRequest.Protocol
会报告 HTTP/2
。
默认情况下将启用 HTTP/2
。 如果未建立 HTTP/2
连接,连接会回退到 HTTP/1.1
。 在 Windows 的未来版本中,将提供 HTTP/2 配置标志,包括使用 HTTP.sys
禁用 HTTP/2
的功能。
对 Kerberos
进行内核模式身份验证
HTTP.sys
通过 Kerberos
身份验证协议委托给内核模式身份验证。 Kerberos
和 HTTP.sys
不支持用户模式身份验证。 必须使用计算机帐户来解密从 Active Directory
获取的并由客户端转发到服务器的 Kerberos
令牌/票证,以便对用户进行身份验证。 注册主机的服务主体名称 (SPN),而不是应用的用户。
如何使用 HTTP.sys
配置 ASP.NET Core 应用以使用 HTTP.sys
-
使用
Microsoft.AspNetCore.App metapackage
(nuget.org)(ASP.NET Core 2.1 或更高版本)时,不需要项目文件中的包引用。 未使用Microsoft.AspNetCore.App
元包时,向 Microsoft.AspNetCore.Server.HttpSys 添加包引用。 -
生成 Web 主机时调用
UseHttpSys
扩展方法,同时指定所需的HttpSysOptions
:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseHttpSys(options =>
{
// The following options are set to default values.
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
options.UrlPrefixes.Add("http://localhost:5000");
});
通过注册表设置处理其他 HTTP.sys
配置。
HTTP.sys 选项
Property | 说明 | 默认 |
---|---|---|
AllowSynchronousIO | 控制是否允许 HttpContext.Request.Body 和 HttpContext.Response.Body 的同步输入/输出。 | True |
Authentication.AllowAnonymous | 允许匿名请求。 | True |
Authentication.Schemes | 指定允许的身份验证方案。 可能在处理侦听器之前随时修改。 通过 AuthenticationSchemes 枚举 Basic、Kerberos、Negotiate、None 和 NTLM 提供值。 | None |
EnableResponseCaching | 尝试内核模式缓存,响应合格的标头。 该响应可能不包括 Set-Cookie、Vary 或 Pragma 标头。 它必须包括属性为 public 的 Cache-Control 标头和 shared-max-age 或 max-age 值,或 Expires 标头。 | True |
MaxAccepts | 最大并发接受数量。 | 5 × 环境。 |
ProcessorCount | ||
MaxConnections | 要接受的最大并发连接数。 使用 -1 实现无限。 通过 null 使用注册表的计算机范围内的设置。 | null |
(无限制) | ||
MaxRequestBodySize | 请参阅 MaxRequestBodySize 部分。 | 30000000 个字节 |
(~28.6 MB) | ||
RequestQueueLimit | 队列中允许的最大请求数。 | 1000 |
ThrowWriteExceptions | 指示由于客户端断开连接而失败的响应主体写入应引发异常还是正常完成。 | False |
(正常完成) | ||
Timeouts | 公开 HTTP.sys TimeoutManager 配置,也可以在注册表中进行配置。 请访问 API 链接详细了解每个设置,包括默认值: | |
TimeoutManager.DrainEntityBody – HTTP 服务器 API 对保持的连接消耗实体正文的时间上限。 | ||
TimeoutManager.EntityBody – 请求实体正文到达的时间上限。 | ||
TimeoutManager.HeaderWait – HTTP 服务器 API 分析请求头的时间上限。 | ||
TimeoutManager.IdleConnection – 空闲连接存在的时间上限。 | ||
TimeoutManager.MinSendBytesPerSecond – 响应的最小发送速率。 | ||
TimeoutManager.RequestQueue – 请求在被应用选择前在请求队列中保留的时间上限。 | ||
UrlPrefixes | 指定要向 HTTP.sys 注册的 UrlPrefixCollection。 最有用的是 UrlPrefixCollection.Add,它用于将前缀添加到集合中。 可能在处理侦听器之前随时对这些设置进行修改。 |
MaxRequestBodySize
允许的请求正文的最大大小(以字节计)。 当设置为 null
时,最大请求正文大小不受限制。 此限制不会影响升级后的连接,这始终不受限制。
在 ASP.NET Core MVC 应用中为单个 IActionResult
替代限制的推荐方法是在操作方法上使用 RequestSizeLimitAttribute
属性:
[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()
如果在应用开始读取请求后尝试配置请求限制,则会引发异常。 IsReadOnly
属性可用于指示 MaxRequestBodySize
属性是否处于只读状态。只读状态意味着已经太迟了,无法配置限制。
如果应用应替代每个请求的 MaxRequestBodySize
,请使用 IHttpMaxRequestBodySizeFeature
:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILogger<Startup> logger, IServer server)
{
app.Use(async (context, next) =>
{
context.Features.Get<IHttpMaxRequestBodySizeFeature>()
.MaxRequestBodySize = 10 * 1024;
var serverAddressesFeature =
app.ServerFeatures.Get<IServerAddressesFeature>();
var addresses = string.Join(", ", serverAddressesFeature?.Addresses);
logger.LogInformation($"Addresses: {addresses}");
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// Enable HTTPS Redirection Middleware when hosting the app securely.
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
-
如果使用的是 Visual Studio,请确保应用未经配置以运行 IIS 或 IIS Express。
在 Visual Studio 中,默认启动配置文件是针对
IIS Express
的。 若要作为控制台应用运行该项目,请手动更改所选配置文件,如以下屏幕截图中所示:
配置 Windows Server
-
确定要为应用打开的端口,并使用 Windows 防火墙或 PowerShell cmdlet 打开防火墙端口,以允许流量到达
HTTP.sys
。 在部署到 Azure VM 时,在网络安全组
中打开端口。 在以下命令和应用配置中,使用的是端口 443。 -
如果需要,获取并安装
X.509
证书。在 Windows 上,可使用
New-SelfSignedCertificate PowerShell cmdlet
创建自签名证书。 有关不支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1。在服务器的“本地计算机” > “个人”存储中,安装自签名证书或 CA 签名证书。
-
如果应用为
框架相关部署
,则安装.NET Core
、.NET Framework
或两者(如果应用是面向 .NET Framework 的 .NET Core 应用)。- .NET Core – 如果应用需要 .NET Core,请从 .NET Core 下载页获取并运行
.NET Core
运行时安装程序。 请勿在服务器上安装完整 SDK。 - .NET Framework – 如果应用需要
.NET Framework
,请参阅.NET Framework 安装指南
。 安装所需的.NET Framework
。 可以从 .NET Core 下载页获取最新.NET Framework
的安装程序。
如果应用是
独立式部署
,应用在部署中包含运行时。 无需在服务器上安装任何框架。 - .NET Core – 如果应用需要 .NET Core,请从 .NET Core 下载页获取并运行
-
在应用中配置 URL 和端口。
默认情况下,ASP.NET Core 绑定到
http://localhost:5000
。 若要配置 URL 前缀和端口,可采用以下方法:UseUrls
urls
命令行参数ASPNETCORE_URLS
环境变量UrlPrefixes
下面的代码示例展示了如何对端口 443 结合使用
UrlPrefixes
和服务器的本地 IP 地址10.0.0.4
:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
// Server local IP address: 10.0.0.4
options.UrlPrefixes.Add("https://10.0.0.4:443");
});
UrlPrefixes
的一个优点是会为格式不正确的前缀立即生成一条错误消息。
UrlPrefixes
中的设置替代 UseUrls
/urls
/ASPNETCORE_URLS
设置。 因此,UseUrls
、urls
和 ASPNETCORE_URLS
环境变量的一个优点是在 Kestrel
和 HTTP.sys
之间切换变得更加容易。 有关更多信息,请参见ASP.NET Core Web 主机
。
HTTP.sys 使用 HTTP 服务器 API UrlPrefix 字符串格式。
警告
不应使用顶级通配符绑定(http://*:80/
和http://+:80
)。 顶级通配符绑定会带来应用安全漏洞。 此行为同时适用于强通配符和弱通配符。 请使用显式主机名或 IP 地址,而不是通配符。 如果可控制整个父域(相对于易受攻击的*.com
),子域通配符绑定(例如,*.mysub.com
)不会构成安全风险。 有关详细信息,请参阅 RFC 7230:第 5.4 节:主机。
-
在服务器上预注册 URL 前缀。
用于配置 HTTP.sys 的内置工具为 netsh.exe。 netsh.exe 用于保留 URL 前缀并分配 X.509 证书。 此工具需要管理员特权。
使用 netsh.exe 工具为应用注册 URL:
netsh http add urlacl url=<URL> user=<USER>
<URL>
– 完全限定的统一资源定位器 (URL)。 不要使用通配符绑定。 请使用有效主机名或本地 IP 地址。 URL 必须包含尾部反斜杠。<USER>
– 指定用户名或用户组名称。
在以下示例中,服务器的本地 IP 地址是 10.0.0.4
:
netsh http add urlacl url=https://10.0.0.4:443/ user=Users
在 URL 注册后,工具响应返回 URL reservation successfully added
。
若要删除已注册的 URL,请使用 delete urlacl
命令:
netsh http delete urlacl url=<URL>
-
在服务器上注册 X.509 证书。
使用 netsh.exe 工具为应用注册证书:
netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
<IP>
– 指定绑定的本地 IP 地址。 不要使用通配符绑定。 请使用有效 IP 地址。<PORT>
– 指定绑定的端口。<THUMBPRINT>
– X.509 证书指纹。<GUID>
– 开发人员生成的表示应用的 GUID,以供参考。
为了便于参考,将 GUID 作为包标记存储在应用中:
- 在 Visual Studio 中:
- 在“解决方案资源管理器”中,右键单击应用,并选择“属性”,以打开应用的项目属性。
- 选择“包”选项卡。
- 在“标记”字段中输入已创建的 GUID。
- 如果使用的不是 Visual Studio:
- 打开应用的项目文件。
- 使用已创建的 GUID,将
<PackageTags>
属性添加到新的或现有的<PropertyGroup>
:
<PropertyGroup>
<PackageTags>9412ee86-c21b-4eb8-bd89-f650fbf44931</PackageTags>
</PropertyGroup>
如下示例中:
- 服务器的本地 IP 地址是
10.0.0.4
。 - 联机随机 GUID 生成器提供
appid
值。
netsh http add sslcert
ipport=10.0.0.4:443
certhash=b66ee04419d4ee37464ab8785ff02449980eae10
appid="{9412ee86-c21b-4eb8-bd89-f650fbf44931}"
在证书注册后,工具响应返回 SSL Certificate successfully added
。
若要删除证书注册,请使用 delete sslcert
命令:
netsh http delete sslcert ipport=<IP>:<PORT>
netsh.exe 的参考文档:
- Netsh Commands for Hypertext Transfer Protocol (HTTP)(超文本传输协议 (HTTP) 的 Netsh 命令)
- UrlPrefix Strings(UrlPrefix 字符串)
-
运行应用。
结合使用 HTTP(而不是 HTTPS)和大于 1024 的端口号绑定到 localhost,无需管理员权限,即可运行应用。 对于其他配置(例如,使用本地 IP 地址或绑定到端口 443),必须有管理员权限才能运行应用。
应用在服务器的公共 IP 地址处响应。 此示例在 Internet 上的公共 IP 地址
104.214.79.47
处访问服务器。此示例使用的是开发证书。 在绕过浏览器的不受信任证书警告后,页面安全加载。
代理服务器和负载均衡器方案
如果应用由 HTTP.sys
托管并且与来自 Internet
或公司网络的请求进行交互,当在代理服务器和负载均衡器后托管时,可能需要其他配置。 有关详细信息,请参阅配置 ASP.NET Core 以使用代理服务器和负载均衡器
。