Note
此版本不是本文的最新版本。 有关当前发布,请参阅本文的 .NET 10 版本。
Warning
不再支持此版本的 ASP.NET Core。 有关详细信息,请参阅 .NET 和 .NET 核心支持策略。 请参阅本文的 .NET 10 版本以获取当前发布的信息。
作者:Tom Dykstra 和 Chris Ross
HTTP.sys 是一个只在 Windows 上运行的用于 ASP.NET Core 的 web 服务器。 HTTP.sys 是 Kestrel 服务器的替代选择,提供了一些 Kestrel 不提供的功能。
Important
HTTP.sys 与
HTTP.sys 支持以下功能:
- Windows身份验证
- 端口共享
- 具有 SNI 的 HTTPS
- HTTP/2 over TLS (Windows 10或更高版本)
- HTTP/3 over TLS (Windows 11 或更高版本)
- 直接文件传输
- 响应缓存
- WebSocket (Windows 8 或更高版本)
- 可自定义的安全描述符
- 自动内存池逐出
支持Windows版本:
- Windows 7或更高版本
- Windows Server 2008 R2 或更高版本
何时使用 HTTP.sys
HTTP.sys 对于以下情形的部署来说很有用:
需要将服务器直接暴露到 Internet,而不使用 IIS。
内部部署需要 Kestrel 中没有的功能。 有关详细信息,请参阅 Kestrel 与 HTTP.sys
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 的功能。
HTTP/3 支持
满足以下基本要求时,将为 ASP.NET Core应用启用 HTTP/3:
- Windows Server 2022/Windows 11 或更高版本
- 使用
httpsURL 绑定。 - 已设置EnableHttp3 注册表项。
上述 Windows 11 预览版可能需要使用 Windows Insider 内部版本。
HTTP/3 是通过 alt-svc 标头作为从 HTTP/1.1 或 HTTP/2 的升级发现的。 这意味着,在切换到 HTTP/3 之前,第一个请求通常使用 HTTP/1.1 或 HTTP/2。 Http.Sys 不会自动添加 alt-svc 标头,它必须由应用程序添加。 以下代码是添加 alt-svc 响应头的中间件示例。
app.Use((context, next) =>
{
context.Response.Headers.AltSvc = "h3=\":443\"";
return next(context);
});
将前面的代码提前放在请求管道中。
Http.Sys 还支持发送 AltSvc HTTP/2 协议消息,而不是通过响应标头来通知客户端 HTTP/3 可用。 请参阅 EnableAltSvc 注册表项。
Note
这需要使用主机名而不是 IP 地址的 netsh sslcert 绑定。 在以下命令中,将ipport替换为hostnameport,然后将netsh http add sslcert命令中的 IP 地址替换为主机名,例如www.example.com。 还有一个已知问题是,使用hostnameport会失败,除非指定了certstorename参数。 默认情况下,使用 certstorename=MY。
对 Kerberos 进行内核模式身份验证
HTTP.sys 使用 Kerberos 身份验证协议进行内核模式身份验证委托。 Kerberos 和 HTTP.sys 不支持用户模式身份验证。 计算机帐户必须用于解密从Active Directory获取的 Kerberos 令牌/票证,并由客户端转发到服务器以对用户进行身份验证。 应为主机而非应用的用户注册服务主体名称 (SPN)。
对内核模式响应缓冲的支持
在某些场景下,高延迟的大量小型写入可能会对 HTTP.sys 造成重大的性能影响。 这种影响是由于 Pipe 实现中缺少 HTTP.sys 缓冲区。 为了在这些场景中提高性能,HTTP.sys 中包含了对响应缓冲的支持。 通过将 HttpSysOptions.EnableKernelResponseBuffering 设置为 true 来启用缓冲。
响应缓冲应由执行同步 I/O 或异步 I/O 且一次不超过一个未完成写入的应用来启用。 在这些方案中,响应缓冲可以在高延迟连接上显著提高吞吐量。
使用异步 I/O 并且可能同时有多个写入未完成的应用程序不应使用此标志。 通过 HTTP.Sys 启用此标志可能会导致 CPU 和内存使用率升高。
如何使用 HTTP.sys
将 ASP.NET Core应用配置为使用 HTTP.sys
生成主机时调用 UseHttpSys 扩展方法,指定所有必需的 HttpSysOptions。 以下示例将选项设置为其默认值:
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys(options =>
{
options.AllowSynchronousIO = false;
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30_000_000;
options.UrlPrefixes.Add("http://localhost:5005");
});
builder.Services.AddRazorPages();
var app = builder.Build();
通过注册表设置处理其他 HTTP.sys 配置。
有关 HTTP.sys 选项的详细信息,请参阅 HttpSysOptions。
自定义安全描述符
HTTP.sys 中的 请求队列 是一种内核级结构,可以临时存储传入的 HTTP 请求,直到应用程序准备好处理这些请求。 使用 上的 HttpSysOptions 属性管理对请求队列的访问。 配置 HTTP.sys 服务器时,将其设置为 GenericSecurityDescriptor 实例。
通过自定义安全描述符,可以允许或拒绝对请求队列的特定用户或组的访问权限。 在希望在操作系统级别限制或委托 HTTP.sys 请求处理的情况下,这非常有用。
例如,以下代码允许所有经过身份验证的用户,但拒绝来宾:
using System.Security.AccessControl;
using System.Security.Principal;
using Microsoft.AspNetCore.Server.HttpSys;
// Create a new security descriptor
var securityDescriptor = new CommonSecurityDescriptor(isContainer: false, isDS: false, sddlForm: string.Empty);
// Create a discretionary access control list (DACL)
var dacl = new DiscretionaryAcl(isContainer: false, isDS: false, capacity: 2);
dacl.AddAccess(
AccessControlType.Allow,
new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
-1,
InheritanceFlags.None,
PropagationFlags.None
);
dacl.AddAccess(
AccessControlType.Deny,
new SecurityIdentifier(WellKnownSidType.BuiltinGuestsSid, null),
-1,
InheritanceFlags.None,
PropagationFlags.None
);
// Assign the DACL to the security descriptor
securityDescriptor.DiscretionaryAcl = dacl;
// Configure HTTP.sys options
var builder = WebApplication.CreateBuilder();
builder.WebHost.UseHttpSys(options =>
{
options.RequestQueueSecurityDescriptor = securityDescriptor;
});
仅当创建新请求队列时,该 RequestQueueSecurityDescriptor 属性才适用。 该属性不会影响现有请求队列。
MaxRequestBodySize
允许的请求正文的最大大小(以字节计)。 当设置为 null 时,最大请求正文大小不受限制。 此限制不会影响升级后的连接,这始终不受限制。
在 ASP.NET Core MVC 应用中覆盖单个 IActionResult 限制的建议方法是对操作方法使用 RequestSizeLimitAttribute 属性:
[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()
如果在应用开始读取请求后尝试配置请求限制,则会引发异常。
IsReadOnly 属性可用于指示 MaxRequestBodySize 属性是否处于只读状态。只读状态意味着已经太迟了,无法配置限制。
如果应用应替代每个请求的 MaxRequestBodySize,请使用 IHttpMaxRequestBodySizeFeature:
app.Use((context, next) =>
{
context.Features.GetRequiredFeature<IHttpMaxRequestBodySizeFeature>()
.MaxRequestBodySize = 10 * 1024;
var server = context.RequestServices
.GetRequiredService<IServer>();
var serverAddressesFeature = server.Features
.GetRequiredFeature<IServerAddressesFeature>();
var addresses = string.Join(", ", serverAddressesFeature.Addresses);
var loggerFactory = context.RequestServices
.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
logger.LogInformation("Addresses: {addresses}", addresses);
return next(context);
});
如果使用Visual Studio,请确保应用未配置为运行 IIS 或 IIS Express。
在Visual Studio中,默认启动配置文件适用于 IIS Express。 若要作为控制台应用运行该项目,请手动更改所选配置文件,如以下屏幕截图中所示:
配置Windows Server
确定要为应用打开的端口,并使用 Windows Firewall 或 New-NetFirewallRule PowerShell cmdlet 打开防火墙端口以允许流量到达 HTTP.sys。 在以下命令和应用配置中,使用的是端口 443。
部署到 Azure VM 时,请在 Network 安全组中打开端口。 在以下命令和应用配置中,使用的是端口 443。
如果需要,获取并安装 X.509 证书。
在Windows上,使用 New-SelfSignedCertificate PowerShell cmdlet 创建自签名证书。 有关不支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1。
在服务器的“本地计算机”存储的“个人”分区中安装自签名证书或 CA 签名证书。
如果应用是依赖于框架的部署,请安装.NET、.NET Framework 或两者(如果应用是面向.NET框架的.NET应用)。
.NET :如果应用需要.NET,请从.NET Downloads .NET Runtime> 安装程序。 请勿在服务器上安装完整 SDK。- .NET Framework:如果应用需要 .NET Framework,请参阅 .NET Framework 安装指南。 安装所需的.NET框架。 最新的 .NET Framework 安装程序可从 .NET Downloads 页获取。
如果应用是独立式部署,应用在部署中包含运行时。 无需在服务器上安装任何框架。
在应用中配置 URL 和端口。
默认情况下,ASP.NET Core绑定到
http://localhost:5000。 若要配置 URL 前缀和端口,可采用以下方法:- UseUrls
-
urls命令行参数 -
ASPNETCORE_URLS环境变量 - UrlPrefixes
下面的代码示例展示了如何在端口 443 上使用 UrlPrefixes 和服务器的本地 IP 地址
10.0.0.4:var builder = WebApplication.CreateBuilder(args); builder.WebHost.UseHttpSys(options => { options.UrlPrefixes.Add("https://10.0.0.4:443"); }); builder.Services.AddRazorPages(); var app = builder.Build();UrlPrefixes的一个优点是会为格式不正确的前缀立即生成一条错误消息。UrlPrefixes中的设置替代UseUrls/urls/ASPNETCORE_URLS设置。 因此,UseUrls、urls和ASPNETCORE_URLS环境变量的一个优点是在 Kestrel 和 HTTP.sys 之间切换变得更加容易。HTTP.sys 可以识别 URL 前缀中的两种通配符:
-
*是一个弱绑定,也称为回退绑定。 如果 URL 前缀为http://*:5000,而其他内容绑定到端口 5000,则不会使用此绑定。 -
+是一个 强绑定。 如果 URL 前缀为http://+:5000,此绑定将在其他端口 5000 绑定之前使用。
有关详细信息,请参阅 UrlPrefix 字符串。
Warning
顶级通配符绑定(
http://*:80/和http://+:80)不应该使用。 顶级通配符绑定会带来应用安全漏洞。 此行为同时适用于强通配符和弱通配符。 请使用显式主机名或 IP 地址,而不是通配符。 如果可控制整个父域(相对于易受攻击的*.mysub.com),子域通配符绑定(例如,*.com)不会构成安全风险。 有关详细信息,请参阅 RFC 9110:第 7.2 节:托管和授权。应用和容器通常只能侦听一个端口(比如端口 80),且没有其他限制(比如主机或路径)。 HTTP_PORTS 和 HTTPS_PORTS 是为 Kestrel 和 HTTP.sys 服务器指定侦听端口的配置密钥。 可以将这些密钥指定为使用
DOTNET_或ASPNETCORE_前缀定义的环境变量,也可以直接通过任何其他配置输入(例如appsettings.json)指定这些密钥。 每个密钥都是一个以分号分隔的端口值列表,如下例所示:ASPNETCORE_HTTP_PORTS=80;8080 ASPNETCORE_HTTPS_PORTS=443;8081上例是以下配置的简写,它指定了方案(HTTP 或 HTTPS)和任何主机或 IP。
ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/HTTP_PORTS 和 HTTPS_PORTS 配置密钥的优先级较低,会被 URLS 或代码中直接提供的值覆盖。 证书仍需通过特定于服务器的 HTTPS 机制单独配置。
这些配置键等同于顶级通配符绑定。 对于开发和容器环境来说,它们很方便,但在运行可能还托管了其他服务的计算机上时请避免使用通配符。
在服务器上预注册 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:
- 通过在
解决方案资源管理器0 中右键单击应用并选择 Properties 打开应用的项目属性。 - 选择“包”选项卡。
- 在“标记”字段中输入您创建的 GUID。
- 通过在
- 不使用Visual Studio时:
打开应用的项目文件。
使用已创建的 GUID,将
<PackageTags>属性添加到新的或现有的<PropertyGroup>:<PropertyGroup> <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags> </PropertyGroup>
在以下示例中:
- 服务器的本地 IP 地址是
10.0.0.4。 - 联机随机 GUID 生成器提供
appid值。
netsh http add sslcert ipport=10.0.0.4:443 certhash=b66ee04419d4ee37464ab8785ff02449980eae10 appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"在证书注册后,工具响应返回
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 字符串
-
运行应用。
使用大于 1024 的端口号通过 HTTP(而不是 HTTPS)绑定到 localhost 时,无需管理员权限即可运行应用。 对于其他配置(例如,使用本地 IP 地址或绑定到端口 443),必须有管理员权限才能运行应用。
应用在服务器的公共 IP 地址处响应。 示例中,通过 Internet 上的公共 IP 地址
104.214.79.47来接入服务器。此示例使用的是开发证书。 在绕过浏览器的不受信任证书警告后,页面安全加载。
代理服务器和负载均衡器方案
如果应用由 HTTP.sys 托管并且与来自 Internet 或公司网络的请求进行交互,当在代理服务器和负载均衡器后托管时,可能需要其他配置。 有关详细信息,请参阅 配置 ASP.NET Core以使用代理服务器和负载均衡器。
使用 IHttpSysRequestTimingFeature 获取详细的时间信息
IHttpSysRequestTimingFeature 为请求提供详细的时间信息:
- 使用 QueryPerformanceCounter 获取时间戳。
- 可通过 QueryPerformanceFrequency 获取时间戳频率。
- 时间索引可强制转换为 HttpSysRequestTimingType,这样便可知道时间的具体内容。
- 如果时间不适用于当前请求,该值可能为 0。
- 需要Windows 10版本 2004、Windows Server 2022 或更高版本。
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var timestamps = feature.Timestamps;
for (var i = 0; i < timestamps.Length; i++)
{
var timestamp = timestamps[i];
var timingType = (HttpSysRequestTimingType)i;
logger.LogInformation("Timestamp {timingType}: {timestamp}",
timingType, timestamp);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
IHttpSysRequestTimingFeature.TryGetTimestamp 可检索提供的时间类型的时间戳:
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var timingType = HttpSysRequestTimingType.RequestRoutingEnd;
if (feature.TryGetTimestamp(timingType, out var timestamp))
{
logger.LogInformation("Timestamp {timingType}: {timestamp}",
timingType, timestamp);
}
else
{
logger.LogInformation("Timestamp {timingType}: not available for the "
+ "current request", timingType);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
[IHttpSysRequestTimingFeature.TryGetElapsedTime](/dotnet/api/microsoft.aspnetcore.server.httpsys.ihttpsysrequesttimingfeature.trygetelapsedtime 返回两个指定计时之间的已用时间:
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var startingTimingType = HttpSysRequestTimingType.RequestRoutingStart;
var endingTimingType = HttpSysRequestTimingType.RequestRoutingEnd;
if (feature.TryGetElapsedTime(startingTimingType, endingTimingType, out var elapsed))
{
logger.LogInformation(
"Elapsed time {startingTimingType} to {endingTimingType}: {elapsed}",
startingTimingType,
endingTimingType,
elapsed);
}
else
{
logger.LogInformation(
"Elapsed time {startingTimingType} to {endingTimingType}:"
+ " not available for the current request.",
startingTimingType,
endingTimingType);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
用于支持 gRPC 的高级 HTTP/2 功能
HTTP.sys 中的其他 HTTP/2 功能支持 gRPC,包括支持响应尾部字段和发送重置帧。
使用 HTTP.sys 运行 gRPC 的要求:
- Windows 11 版本 22000 或更高版本,Windows Server 2022 版本 20348 或更高版本。
- TLS 1.2 或更高版本的连接。
Trailers
HTTP 尾部字段类似于 HTTP 标头字段,不同的是它们是在发送响应正文之后才发送的。 IIS 和 HTTP.sys 仅支持 HTTP/2 响应尾部字段。
if (httpContext.Response.SupportsTrailers())
{
httpContext.Response.DeclareTrailer("trailername");
// Write body
httpContext.Response.WriteAsync("Hello world");
httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}
在前面的示例代码中:
-
SupportsTrailers确保响应支持尾部字段。 -
DeclareTrailer将给定的尾部名称添加到Trailer响应头。 声明响应的尾部数据是可选的,但建议这样做。 如果要调用DeclareTrailer,则必须在发送响应标头之前进行此操作。 -
AppendTrailer追加尾部。
Reset
通过“Reset”,服务器可以使用指定的错误代码重置 HTTP/2 请求。 重置请求被视为中止。
var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);
前述代码示例中的 Reset 指定 INTERNAL_ERROR 错误代码。 有关 HTTP/2 错误代码的详细信息,请访问“HTTP/2 规范错误代码”部分。
Tracing
有关如何从 HTTP.sys 获取跟踪的信息,请参阅 HTTP.sys 可管理性方案。
从内存池自动移除
当应用程序空闲或负载不足时,IIS 和 HTTP.sys 使用的 Kestrel内存池会自动逐出内存块。 该功能会自动运行,无需手动启用或配置。
在 10 之前的 .NET 版本中,池所分配的内存仍被保留,即使未使用时也是如此。 这种自动逐出功能可减少总体内存使用率,并帮助应用程序在不同工作负荷下保持响应。
使用内存池指标
ASP.NET Core服务器实现使用的默认内存池包括指标,可用于监视和分析内存使用模式。 指标位于"Microsoft.AspNetCore.MemoryPool"名称下。
有关指标及其用法的信息,请参阅ASP.NET Core指标。
管理内存池
除了通过逐出不需要的内存块来有效使用内存池外,ASP.NET Core还提供内置的 IMemoryPoolFactory 和实现。 它通过依赖项注入使实现可供应用程序使用。
下面的代码示例演示了一个简单的后台服务,该服务使用内置的内存池工厂实现来创建内存池。 这些池受益于自动逐出功能:
public class MyBackgroundService : BackgroundService
{
private readonly MemoryPool<byte> _memoryPool;
public MyBackgroundService(IMemoryPoolFactory<byte> factory)
{
_memoryPool = factory.Create();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await Task.Delay(20, stoppingToken);
// do work that needs memory
// consider checking _memoryPool.MaxBufferSize
var rented = _memoryPool.Rent(100);
rented.Dispose();
}
catch (OperationCanceledException)
{
return;
}
}
}
}
若要使用自定义内存池工厂,请创建一个实现 IMemoryPoolFactory 并将其注册到依赖项注入的类,如以下示例所示。 以这种方式创建的内存池不会受益于自动逐出功能,除非在自定义工厂中实现类似的逐出逻辑:
services.AddSingleton<IMemoryPoolFactory<byte>,
CustomMemoryPoolFactory>();
public class CustomMemoryPoolFactory : IMemoryPoolFactory<byte>
{
public MemoryPool<byte> Create()
{
// Return a custom MemoryPool implementation
// or the default, as is shown here.
return MemoryPool<byte>.Shared;
}
}
使用内存池时,请注意池的 MaxBufferSize。
其他资源
HTTP.sys 是一个只在 Windows 上运行的用于 ASP.NET Core 的 web 服务器。 HTTP.sys 是 Kestrel 服务器的替代选择,提供了一些 Kestrel 不提供的功能。
Important
HTTP.sys 与
HTTP.sys 支持以下功能:
- Windows身份验证
- 端口共享
- 具有 SNI 的 HTTPS
- HTTP/2 over TLS (Windows 10或更高版本)
- 直接文件传输
- 响应缓存
- WebSocket (Windows 8 或更高版本)
支持Windows版本:
- Windows 7或更高版本
- Windows Server 2008 R2 或更高版本
何时使用 HTTP.sys
HTTP.sys 对于以下情形的部署来说很有用:
需要将服务器直接暴露到 Internet,而不使用 IIS。
内部部署需要 Kestrel 中没有的功能。 有关详细信息,请参阅 Kestrel 与 HTTP.sys
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 的功能。
HTTP/3 支持
满足以下基本要求时,将为 ASP.NET Core应用启用 HTTP/3:
- Windows Server 2022/Windows 11 或更高版本
- 使用
httpsURL 绑定。 - 已设置EnableHttp3 注册表项。
上述 Windows 11 预览版可能需要使用 Windows Insider 内部版本。
HTTP/3 是通过 alt-svc 标头作为从 HTTP/1.1 或 HTTP/2 的升级发现的。 这意味着,在切换到 HTTP/3 之前,第一个请求通常使用 HTTP/1.1 或 HTTP/2。 Http.Sys 不会自动添加 alt-svc 标头,它必须由应用程序添加。 以下代码是添加 alt-svc 响应头的中间件示例。
app.Use((context, next) =>
{
context.Response.Headers.AltSvc = "h3=\":443\"";
return next(context);
});
将前面的代码提前放在请求管道中。
Http.Sys 还支持发送 AltSvc HTTP/2 协议消息,而不是通过响应标头来通知客户端 HTTP/3 可用。 请参阅 EnableAltSvc 注册表项。 这需要使用主机名而不是 IP 地址的 netsh sslcert 绑定。
对 Kerberos 进行内核模式身份验证
HTTP.sys 使用 Kerberos 身份验证协议进行内核模式身份验证委托。 Kerberos 和 HTTP.sys 不支持用户模式身份验证。 计算机帐户必须用于解密从Active Directory获取的 Kerberos 令牌/票证,并由客户端转发到服务器以对用户进行身份验证。 应为主机而非应用的用户注册服务主体名称 (SPN)。
如何使用 HTTP.sys
将 ASP.NET Core应用配置为使用 HTTP.sys
生成主机时调用 UseHttpSys 扩展方法,指定所有必需的 HttpSysOptions。 以下示例将选项设置为其默认值:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseHttpSys(options =>
{
options.AllowSynchronousIO = false;
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
options.UrlPrefixes.Add("http://localhost:5005");
});
webBuilder.UseStartup<Startup>();
});
通过注册表设置处理其他 HTTP.sys 配置。
有关 HTTP.sys 选项的详细信息,请参阅 HttpSysOptions。
MaxRequestBodySize
允许的请求正文的最大大小(以字节计)。 当设置为 null 时,最大请求正文大小不受限制。 此限制不会影响升级后的连接,这始终不受限制。
在 ASP.NET Core MVC 应用中覆盖单个 IActionResult 限制的建议方法是对操作方法使用 RequestSizeLimitAttribute 属性:
[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()
如果在应用开始读取请求后尝试配置请求限制,则会引发异常。
IsReadOnly 属性可用于指示 MaxRequestBodySize 属性是否处于只读状态。只读状态意味着已经太迟了,无法配置限制。
如果应用应替代每个请求的 MaxRequestBodySize,请使用 IHttpMaxRequestBodySizeFeature:
public void Configure(IApplicationBuilder app, IWebHostEnvironment 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}", addresses);
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
如果使用Visual Studio,请确保应用未配置为运行 IIS 或 IIS Express。
在Visual Studio中,默认启动配置文件适用于 IIS Express。 若要作为控制台应用运行该项目,请手动更改所选配置文件,如以下屏幕截图中所示:
配置Windows Server
确定要为应用打开的端口,并使用 Windows Firewall 或 New-NetFirewallRule PowerShell cmdlet 打开防火墙端口以允许流量到达 HTTP.sys。 在以下命令和应用配置中,使用的是端口 443。
部署到 Azure VM 时,请在 Network 安全组中打开端口。 在以下命令和应用配置中,使用的是端口 443。
如果需要,获取并安装 X.509 证书。
在Windows上,使用 New-SelfSignedCertificate PowerShell cmdlet 创建自签名证书。 有关不支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1。
在服务器的“本地计算机”存储的“个人”分区中安装自签名证书或 CA 签名证书。
如果应用是依赖于框架的部署,请安装.NET、.NET Framework 或两者(如果应用是面向.NET框架的.NET应用)。
.NET :如果应用需要.NET,请从.NET Downloads .NET Runtime> 安装程序。 请勿在服务器上安装完整 SDK。- .NET Framework:如果应用需要 .NET Framework,请参阅 .NET Framework 安装指南。 安装所需的.NET框架。 最新的 .NET Framework 安装程序可从 .NET Downloads 页获取。
如果应用是独立式部署,应用在部署中包含运行时。 无需在服务器上安装任何框架。
在应用中配置 URL 和端口。
默认情况下,ASP.NET Core绑定到
http://localhost:5000。 若要配置 URL 前缀和端口,可采用以下方法:- UseUrls
-
urls命令行参数 -
ASPNETCORE_URLS环境变量 - UrlPrefixes
下面的代码示例展示了如何在端口 443 上使用 UrlPrefixes 和服务器的本地 IP 地址
10.0.0.4:public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseHttpSys(options => { options.UrlPrefixes.Add("https://10.0.0.4:443"); }); webBuilder.UseStartup<Startup>(); });UrlPrefixes的一个优点是会为格式不正确的前缀立即生成一条错误消息。UrlPrefixes中的设置替代UseUrls/urls/ASPNETCORE_URLS设置。 因此,UseUrls、urls和ASPNETCORE_URLS环境变量的一个优点是在 Kestrel 和 HTTP.sys 之间切换变得更加容易。HTTP.sys 使用 HTTP 服务器 API UrlPrefix 字符串格式。
Warning
顶级通配符绑定(
http://*:80/和http://+:80)不应该使用。 顶级通配符绑定会带来应用安全漏洞。 此行为同时适用于强通配符和弱通配符。 请使用显式主机名或 IP 地址,而不是通配符。 如果可控制整个父域(相对于易受攻击的*.mysub.com),子域通配符绑定(例如,*.com)不会构成安全风险。 有关详细信息,请参阅 RFC 9110:第 7.2 节:托管和授权。在服务器上预注册 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:
- 通过在
解决方案资源管理器0 中右键单击应用并选择 Properties 打开应用的项目属性。 - 选择“包”选项卡。
- 在“标记”字段中输入您创建的 GUID。
- 通过在
- 不使用Visual Studio时:
打开应用的项目文件。
使用已创建的 GUID,将
<PackageTags>属性添加到新的或现有的<PropertyGroup>:<PropertyGroup> <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags> </PropertyGroup>
在以下示例中:
- 服务器的本地 IP 地址是
10.0.0.4。 - 联机随机 GUID 生成器提供
appid值。
netsh http add sslcert ipport=10.0.0.4:443 certhash=b66ee04419d4ee37464ab8785ff02449980eae10 appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"在证书注册后,工具响应返回
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 字符串
-
运行应用。
使用大于 1024 的端口号通过 HTTP(而不是 HTTPS)绑定到 localhost 时,无需管理员权限即可运行应用。 对于其他配置(例如,使用本地 IP 地址或绑定到端口 443),必须有管理员权限才能运行应用。
应用在服务器的公共 IP 地址处响应。 示例中,通过 Internet 上的公共 IP 地址
104.214.79.47来接入服务器。此示例使用的是开发证书。 在绕过浏览器的不受信任证书警告后,页面安全加载。
代理服务器和负载均衡器方案
如果应用由 HTTP.sys 托管并且与来自 Internet 或公司网络的请求进行交互,当在代理服务器和负载均衡器后托管时,可能需要其他配置。 有关详细信息,请参阅 配置 ASP.NET Core以使用代理服务器和负载均衡器。
用于支持 gRPC 的高级 HTTP/2 功能
HTTP.sys 中的其他 HTTP/2 功能支持 gRPC,包括支持响应尾部字段和发送重置帧。
使用 HTTP.sys 运行 gRPC 的要求:
- Windows 11 版本 22000 或更高版本,Windows Server 2022 版本 20348 或更高版本。
- TLS 1.2 或更高版本的连接。
Trailers
HTTP 尾部字段类似于 HTTP 标头字段,不同的是它们是在发送响应正文之后才发送的。 IIS 和 HTTP.sys 仅支持 HTTP/2 响应尾部字段。
if (httpContext.Response.SupportsTrailers())
{
httpContext.Response.DeclareTrailer("trailername");
// Write body
httpContext.Response.WriteAsync("Hello world");
httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}
在前面的示例代码中:
-
SupportsTrailers确保响应支持尾部字段。 -
DeclareTrailer将给定的尾部名称添加到Trailer响应头。 声明响应的尾部数据是可选的,但建议这样做。 如果要调用DeclareTrailer,则必须在发送响应标头之前进行此操作。 -
AppendTrailer追加尾部。
Reset
通过“Reset”,服务器可以使用指定的错误代码重置 HTTP/2 请求。 重置请求被视为中止。
var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);
前述代码示例中的 Reset 指定 INTERNAL_ERROR 错误代码。 有关 HTTP/2 错误代码的详细信息,请访问“HTTP/2 规范错误代码”部分。
其他资源
HTTP.sys 是一个只在 Windows 上运行的用于 ASP.NET Core 的 web 服务器。 HTTP.sys 是 Kestrel 服务器的替代选择,提供了一些 Kestrel 不提供的功能。
Important
HTTP.sys 与
HTTP.sys 支持以下功能:
- Windows身份验证
- 端口共享
- 具有 SNI 的 HTTPS
- HTTP/2 over TLS (Windows 10或更高版本)
- 直接文件传输
- 响应缓存
- WebSocket (Windows 8 或更高版本)
支持Windows版本:
- Windows 7或更高版本
- Windows Server 2008 R2 或更高版本
何时使用 HTTP.sys
HTTP.sys 对于以下情形的部署来说很有用:
需要将服务器直接暴露到 Internet,而不使用 IIS。
内部部署需要 Kestrel 中没有的功能。 有关详细信息,请参阅 Kestrel 与 HTTP.sys
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
生成主机时调用 UseHttpSys 扩展方法,指定所有必需的 HttpSysOptions。 以下示例将选项设置为其默认值:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseHttpSys(options =>
{
options.AllowSynchronousIO = false;
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
options.UrlPrefixes.Add("http://localhost:5005");
});
webBuilder.UseStartup<Startup>();
});
通过注册表设置处理其他 HTTP.sys 配置。
HTTP.sys 选项
| Property | Description | Default |
|---|---|---|
| AllowSynchronousIO | 控制是否允许 HttpContext.Request.Body 和 HttpContext.Response.Body 的同步输入/输出。 |
false |
| 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 |
| Http503Verbosity | 由于限流条件而拒绝请求时的 HTTP.sys 行为。 |
Http503VerbosityLevel。 基本 |
| MaxAccepts | 最大并发接受数量。 | 5 × 环境。 处理器计数 |
| MaxConnections | 要接受的最大并发连接数。 使用 -1 实现无限。 通过 null 使用注册表的系统设置。 |
null(machine-wide setting) |
| MaxRequestBodySize | 请参阅 MaxRequestBodySize 部分。 | 30000000 字节 (~28.6 MB) |
| RequestQueueLimit | 可以排队的最大请求数。 | 1000 |
RequestQueueMode |
这指示服务器是否负责创建和配置请求队列,或是否应附加到现有队列。 附加到现有队列时,大多数现有配置选项不适用。 |
RequestQueueMode.Create |
RequestQueueName |
HTTP.sys 请求队列的名称。 |
null(匿名队列) |
| ThrowWriteExceptions | 指示由于客户端断开连接而失败的响应主体写入应引发异常还是正常完成。 | false(完成正常) |
| Timeouts | 公开 HTTP.sys TimeoutManager 配置,也可以在注册表中进行配置。 请访问 API 链接详细了解每个设置,包括默认值:
|
|
| UrlPrefixes | 指定注册表中的UrlPrefixCollection以向 HTTP.sys 注册。 最有用的是 UrlPrefixCollection.Add,它用于将前缀添加到集合中。 这些设置可以在释放侦听器之前随时进行修改。 |
MaxRequestBodySize
允许的请求正文的最大大小(以字节计)。 当设置为 null 时,最大请求正文大小不受限制。 此限制不会影响升级后的连接,这始终不受限制。
在 ASP.NET Core MVC 应用中覆盖单个 IActionResult 限制的建议方法是对操作方法使用 RequestSizeLimitAttribute 属性:
[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()
如果在应用开始读取请求后尝试配置请求限制,则会引发异常。
IsReadOnly 属性可用于指示 MaxRequestBodySize 属性是否处于只读状态。只读状态意味着已经太迟了,无法配置限制。
如果应用应替代每个请求的 MaxRequestBodySize,请使用 IHttpMaxRequestBodySizeFeature:
public void Configure(IApplicationBuilder app, IWebHostEnvironment 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}", addresses);
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
如果使用Visual Studio,请确保应用未配置为运行 IIS 或 IIS Express。
在Visual Studio中,默认启动配置文件适用于 IIS Express。 若要作为控制台应用运行该项目,请手动更改所选配置文件,如以下屏幕截图中所示:
配置Windows Server
确定要为应用打开的端口,并使用 Windows Firewall 或 New-NetFirewallRule PowerShell cmdlet 打开防火墙端口以允许流量到达 HTTP.sys。 在以下命令和应用配置中,使用的是端口 443。
部署到 Azure VM 时,请在 Network 安全组中打开端口。 在以下命令和应用配置中,使用的是端口 443。
如果需要,获取并安装 X.509 证书。
在Windows上,使用 New-SelfSignedCertificate PowerShell cmdlet 创建自签名证书。 有关不支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1。
在服务器的“本地计算机”存储的“个人”分区中安装自签名证书或 CA 签名证书。
如果应用是依赖于框架的部署,请安装.NET、.NET Framework 或两者(如果应用是面向.NET框架的.NET应用)。
.NET :如果应用需要.NET,请从.NET Downloads .NET Runtime> 安装程序。 请勿在服务器上安装完整 SDK。- .NET Framework:如果应用需要 .NET Framework,请参阅 .NET Framework 安装指南。 安装所需的.NET框架。 最新的 .NET Framework 安装程序可从 .NET Downloads 页获取。
如果应用是独立式部署,应用在部署中包含运行时。 无需在服务器上安装任何框架。
在应用中配置 URL 和端口。
默认情况下,ASP.NET Core绑定到
http://localhost:5000。 若要配置 URL 前缀和端口,可采用以下方法:- UseUrls
-
urls命令行参数 -
ASPNETCORE_URLS环境变量 - UrlPrefixes
下面的代码示例展示了如何在端口 443 上使用 UrlPrefixes 和服务器的本地 IP 地址
10.0.0.4:public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseHttpSys(options => { options.UrlPrefixes.Add("https://10.0.0.4:443"); }); webBuilder.UseStartup<Startup>(); });UrlPrefixes的一个优点是会为格式不正确的前缀立即生成一条错误消息。UrlPrefixes中的设置替代UseUrls/urls/ASPNETCORE_URLS设置。 因此,UseUrls、urls和ASPNETCORE_URLS环境变量的一个优点是在 Kestrel 和 HTTP.sys 之间切换变得更加容易。HTTP.sys 使用 HTTP 服务器 API UrlPrefix 字符串格式。
Warning
顶级通配符绑定(
http://*:80/和http://+:80)不应该使用。 顶级通配符绑定会带来应用安全漏洞。 此行为同时适用于强通配符和弱通配符。 请使用显式主机名或 IP 地址,而不是通配符。 如果可控制整个父域(相对于易受攻击的*.mysub.com),子域通配符绑定(例如,*.com)不会构成安全风险。 有关详细信息,请参阅 RFC 9110:第 7.2 节:托管和授权。在服务器上预注册 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:
- 通过在
解决方案资源管理器0 中右键单击应用并选择 Properties 打开应用的项目属性。 - 选择“包”选项卡。
- 在“标记”字段中输入您创建的 GUID。
- 通过在
- 不使用Visual Studio时:
打开应用的项目文件。
使用已创建的 GUID,将
<PackageTags>属性添加到新的或现有的<PropertyGroup>:<PropertyGroup> <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags> </PropertyGroup>
在以下示例中:
- 服务器的本地 IP 地址是
10.0.0.4。 - 联机随机 GUID 生成器提供
appid值。
netsh http add sslcert ipport=10.0.0.4:443 certhash=b66ee04419d4ee37464ab8785ff02449980eae10 appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"在证书注册后,工具响应返回
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 字符串
-
运行应用。
使用大于 1024 的端口号通过 HTTP(而不是 HTTPS)绑定到 localhost 时,无需管理员权限即可运行应用。 对于其他配置(例如,使用本地 IP 地址或绑定到端口 443),必须有管理员权限才能运行应用。
应用在服务器的公共 IP 地址处响应。 示例中,通过 Internet 上的公共 IP 地址
104.214.79.47来接入服务器。此示例使用的是开发证书。 在绕过浏览器的不受信任证书警告后,页面安全加载。
代理服务器和负载均衡器方案
如果应用由 HTTP.sys 托管并且与来自 Internet 或公司网络的请求进行交互,当在代理服务器和负载均衡器后托管时,可能需要其他配置。 有关详细信息,请参阅 配置 ASP.NET Core以使用代理服务器和负载均衡器。
用于支持 gRPC 的高级 HTTP/2 功能
HTTP.sys 中的其他 HTTP/2 功能支持 gRPC,包括支持响应尾部字段和发送重置帧。
使用 HTTP.sys 运行 gRPC 的要求:
- Windows 10、OS 内部版本 19041.508 或更高版本
- TLS 1.2 或更高版本的连接
Trailers
HTTP 尾部字段类似于 HTTP 标头字段,不同的是它们是在发送响应正文之后才发送的。 IIS 和 HTTP.sys 仅支持 HTTP/2 响应尾部字段。
if (httpContext.Response.SupportsTrailers())
{
httpContext.Response.DeclareTrailer("trailername");
// Write body
httpContext.Response.WriteAsync("Hello world");
httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}
在前面的示例代码中:
-
SupportsTrailers确保响应支持尾部字段。 -
DeclareTrailer将给定的尾部名称添加到Trailer响应头。 声明响应的尾部数据是可选的,但建议这样做。 如果要调用DeclareTrailer,则必须在发送响应标头之前进行此操作。 -
AppendTrailer追加尾部。
Reset
通过“Reset”,服务器可以使用指定的错误代码重置 HTTP/2 请求。 重置请求被视为中止。
var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);
前述代码示例中的 Reset 指定 INTERNAL_ERROR 错误代码。 有关 HTTP/2 错误代码的详细信息,请访问“HTTP/2 规范错误代码”部分。
其他资源
HTTP.sys 是一个只在 Windows 上运行的用于 ASP.NET Core 的 web 服务器。 HTTP.sys 是 Kestrel 服务器的替代选择,提供了一些 Kestrel 不提供的功能。
Important
HTTP.sys 与
HTTP.sys 支持以下功能:
- Windows身份验证
- 端口共享
- 具有 SNI 的 HTTPS
- HTTP/2 over TLS (Windows 10或更高版本)
- HTTP/3 over TLS (Windows 11 或更高版本)
- 直接文件传输
- 响应缓存
- WebSocket (Windows 8 或更高版本)
- 可自定义的安全描述符
支持Windows版本:
- Windows 7或更高版本
- Windows Server 2008 R2 或更高版本
何时使用 HTTP.sys
HTTP.sys 对于以下情形的部署来说很有用:
需要将服务器直接暴露到 Internet,而不使用 IIS。
内部部署需要 Kestrel 中没有的功能。 有关详细信息,请参阅 Kestrel 与 HTTP.sys
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 的功能。
HTTP/3 支持
满足以下基本要求时,将为 ASP.NET Core应用启用 HTTP/3:
- Windows Server 2022/Windows 11 或更高版本
- 使用
httpsURL 绑定。 - 已设置EnableHttp3 注册表项。
上述 Windows 11 预览版可能需要使用 Windows Insider 内部版本。
HTTP/3 是通过 alt-svc 标头作为从 HTTP/1.1 或 HTTP/2 的升级发现的。 这意味着,在切换到 HTTP/3 之前,第一个请求通常使用 HTTP/1.1 或 HTTP/2。 Http.Sys 不会自动添加 alt-svc 标头,它必须由应用程序添加。 以下代码是添加 alt-svc 响应头的中间件示例。
app.Use((context, next) =>
{
context.Response.Headers.AltSvc = "h3=\":443\"";
return next(context);
});
将前面的代码提前放在请求管道中。
Http.Sys 还支持发送 AltSvc HTTP/2 协议消息,而不是通过响应标头来通知客户端 HTTP/3 可用。 请参阅 EnableAltSvc 注册表项。 这需要使用主机名而不是 IP 地址的 netsh sslcert 绑定。
对 Kerberos 进行内核模式身份验证
HTTP.sys 使用 Kerberos 身份验证协议进行内核模式身份验证委托。 Kerberos 和 HTTP.sys 不支持用户模式身份验证。 计算机帐户必须用于解密从Active Directory获取的 Kerberos 令牌/票证,并由客户端转发到服务器以对用户进行身份验证。 应为主机而非应用的用户注册服务主体名称 (SPN)。
对内核模式响应缓冲的支持
在某些场景下,高延迟的大量小型写入可能会对 HTTP.sys 造成重大的性能影响。 这种影响是由于 Pipe 实现中缺少 HTTP.sys 缓冲区。 为了在这些场景中提高性能,HTTP.sys 中包含了对响应缓冲的支持。 通过将 HttpSysOptions.EnableKernelResponseBuffering 设置为 true 来启用缓冲。
响应缓冲应由执行同步 I/O 或异步 I/O 且一次不超过一个未完成写入的应用来启用。 在这些方案中,响应缓冲可以在高延迟连接上显著提高吞吐量。
使用异步 I/O 并且可能同时有多个写入未完成的应用程序不应使用此标志。 通过 HTTP.Sys 启用此标志可能会导致 CPU 和内存使用率升高。
如何使用 HTTP.sys
将 ASP.NET Core应用配置为使用 HTTP.sys
生成主机时调用 UseHttpSys 扩展方法,指定所有必需的 HttpSysOptions。 以下示例将选项设置为其默认值:
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys(options =>
{
options.AllowSynchronousIO = false;
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30_000_000;
options.UrlPrefixes.Add("http://localhost:5005");
});
builder.Services.AddRazorPages();
var app = builder.Build();
通过注册表设置处理其他 HTTP.sys 配置。
有关 HTTP.sys 选项的详细信息,请参阅 HttpSysOptions。
MaxRequestBodySize
允许的请求正文的最大大小(以字节计)。 当设置为 null 时,最大请求正文大小不受限制。 此限制不会影响升级后的连接,这始终不受限制。
在 ASP.NET Core MVC 应用中覆盖单个 IActionResult 限制的建议方法是对操作方法使用 RequestSizeLimitAttribute 属性:
[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()
如果在应用开始读取请求后尝试配置请求限制,则会引发异常。
IsReadOnly 属性可用于指示 MaxRequestBodySize 属性是否处于只读状态。只读状态意味着已经太迟了,无法配置限制。
如果应用应替代每个请求的 MaxRequestBodySize,请使用 IHttpMaxRequestBodySizeFeature:
app.Use((context, next) =>
{
context.Features.GetRequiredFeature<IHttpMaxRequestBodySizeFeature>()
.MaxRequestBodySize = 10 * 1024;
var server = context.RequestServices
.GetRequiredService<IServer>();
var serverAddressesFeature = server.Features
.GetRequiredFeature<IServerAddressesFeature>();
var addresses = string.Join(", ", serverAddressesFeature.Addresses);
var loggerFactory = context.RequestServices
.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
logger.LogInformation("Addresses: {addresses}", addresses);
return next(context);
});
如果使用Visual Studio,请确保应用未配置为运行 IIS 或 IIS Express。
在Visual Studio中,默认启动配置文件适用于 IIS Express。 若要作为控制台应用运行该项目,请手动更改所选配置文件,如以下屏幕截图中所示:
配置Windows Server
确定要为应用打开的端口,并使用 Windows Firewall 或 New-NetFirewallRule PowerShell cmdlet 打开防火墙端口以允许流量到达 HTTP.sys。 在以下命令和应用配置中,使用的是端口 443。
部署到 Azure VM 时,请在 Network 安全组中打开端口。 在以下命令和应用配置中,使用的是端口 443。
如果需要,获取并安装 X.509 证书。
在Windows上,使用 New-SelfSignedCertificate PowerShell cmdlet 创建自签名证书。 有关不支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1。
在服务器的“本地计算机”存储的“个人”分区中安装自签名证书或 CA 签名证书。
如果应用是依赖于框架的部署,请安装.NET、.NET Framework 或两者(如果应用是面向.NET框架的.NET应用)。
.NET :如果应用需要.NET,请从.NET Downloads .NET Runtime> 安装程序。 请勿在服务器上安装完整 SDK。- .NET Framework:如果应用需要 .NET Framework,请参阅 .NET Framework 安装指南。 安装所需的.NET框架。 最新的 .NET Framework 安装程序可从 .NET Downloads 页获取。
如果应用是独立式部署,应用在部署中包含运行时。 无需在服务器上安装任何框架。
在应用中配置 URL 和端口。
默认情况下,ASP.NET Core绑定到
http://localhost:5000。 若要配置 URL 前缀和端口,可采用以下方法:- UseUrls
-
urls命令行参数 -
ASPNETCORE_URLS环境变量 - UrlPrefixes
下面的代码示例展示了如何在端口 443 上使用 UrlPrefixes 和服务器的本地 IP 地址
10.0.0.4:var builder = WebApplication.CreateBuilder(args); builder.WebHost.UseHttpSys(options => { options.UrlPrefixes.Add("https://10.0.0.4:443"); }); builder.Services.AddRazorPages(); var app = builder.Build();UrlPrefixes的一个优点是会为格式不正确的前缀立即生成一条错误消息。UrlPrefixes中的设置替代UseUrls/urls/ASPNETCORE_URLS设置。 因此,UseUrls、urls和ASPNETCORE_URLS环境变量的一个优点是在 Kestrel 和 HTTP.sys 之间切换变得更加容易。HTTP.sys 可以识别 URL 前缀中的两种通配符:
-
*是一个弱绑定,也称为回退绑定。 如果 URL 前缀为http://*:5000,而其他内容绑定到端口 5000,则不会使用此绑定。 -
+是一个 强绑定。 如果 URL 前缀为http://+:5000,此绑定将在其他端口 5000 绑定之前使用。
有关详细信息,请参阅 UrlPrefix 字符串。
Warning
顶级通配符绑定(
http://*:80/和http://+:80)不应该使用。 顶级通配符绑定会带来应用安全漏洞。 此行为同时适用于强通配符和弱通配符。 请使用显式主机名或 IP 地址,而不是通配符。 如果可控制整个父域(相对于易受攻击的*.mysub.com),子域通配符绑定(例如,*.com)不会构成安全风险。 有关详细信息,请参阅 RFC 9110:第 7.2 节:托管和授权。应用和容器通常只能侦听一个端口(比如端口 80),且没有其他限制(比如主机或路径)。 HTTP_PORTS 和 HTTPS_PORTS 是为 Kestrel 和 HTTP.sys 服务器指定侦听端口的配置密钥。 可以将这些密钥指定为使用
DOTNET_或ASPNETCORE_前缀定义的环境变量,也可以直接通过任何其他配置输入(例如appsettings.json)指定这些密钥。 每个密钥都是一个以分号分隔的端口值列表,如下例所示:ASPNETCORE_HTTP_PORTS=80;8080 ASPNETCORE_HTTPS_PORTS=443;8081上例是以下配置的简写,它指定了方案(HTTP 或 HTTPS)和任何主机或 IP。
ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/HTTP_PORTS 和 HTTPS_PORTS 配置密钥的优先级较低,会被 URLS 或代码中直接提供的值覆盖。 证书仍需通过特定于服务器的 HTTPS 机制单独配置。
这些配置键等同于顶级通配符绑定。 对于开发和容器环境来说,它们很方便,但在运行可能还托管了其他服务的计算机上时请避免使用通配符。
在服务器上预注册 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:
- 通过在
解决方案资源管理器0 中右键单击应用并选择 Properties 打开应用的项目属性。 - 选择“包”选项卡。
- 在“标记”字段中输入您创建的 GUID。
- 通过在
- 不使用Visual Studio时:
打开应用的项目文件。
使用已创建的 GUID,将
<PackageTags>属性添加到新的或现有的<PropertyGroup>:<PropertyGroup> <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags> </PropertyGroup>
在以下示例中:
- 服务器的本地 IP 地址是
10.0.0.4。 - 联机随机 GUID 生成器提供
appid值。
netsh http add sslcert ipport=10.0.0.4:443 certhash=b66ee04419d4ee37464ab8785ff02449980eae10 appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"在证书注册后,工具响应返回
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 字符串
-
运行应用。
使用大于 1024 的端口号通过 HTTP(而不是 HTTPS)绑定到 localhost 时,无需管理员权限即可运行应用。 对于其他配置(例如,使用本地 IP 地址或绑定到端口 443),必须有管理员权限才能运行应用。
应用在服务器的公共 IP 地址处响应。 示例中,通过 Internet 上的公共 IP 地址
104.214.79.47来接入服务器。此示例使用的是开发证书。 在绕过浏览器的不受信任证书警告后,页面安全加载。
代理服务器和负载均衡器方案
如果应用由 HTTP.sys 托管并且与来自 Internet 或公司网络的请求进行交互,当在代理服务器和负载均衡器后托管时,可能需要其他配置。 有关详细信息,请参阅 配置 ASP.NET Core以使用代理服务器和负载均衡器。
使用 IHttpSysRequestTimingFeature 获取详细的时间信息
IHttpSysRequestTimingFeature 为请求提供详细的时间信息:
- 使用 QueryPerformanceCounter 获取时间戳。
- 可通过 QueryPerformanceFrequency 获取时间戳频率。
- 时间索引可强制转换为 HttpSysRequestTimingType,这样便可知道时间的具体内容。
- 如果时间不适用于当前请求,该值可能为 0。
- 需要Windows 10版本 2004、Windows Server 2022 或更高版本。
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var timestamps = feature.Timestamps;
for (var i = 0; i < timestamps.Length; i++)
{
var timestamp = timestamps[i];
var timingType = (HttpSysRequestTimingType)i;
logger.LogInformation("Timestamp {timingType}: {timestamp}",
timingType, timestamp);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
IHttpSysRequestTimingFeature.TryGetTimestamp 可检索提供的时间类型的时间戳:
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var timingType = HttpSysRequestTimingType.RequestRoutingEnd;
if (feature.TryGetTimestamp(timingType, out var timestamp))
{
logger.LogInformation("Timestamp {timingType}: {timestamp}",
timingType, timestamp);
}
else
{
logger.LogInformation("Timestamp {timingType}: not available for the "
+ "current request", timingType);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
[IHttpSysRequestTimingFeature.TryGetElapsedTime](/dotnet/api/microsoft.aspnetcore.server.httpsys.ihttpsysrequesttimingfeature.trygetelapsedtime 返回两个指定计时之间的已用时间:
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var startingTimingType = HttpSysRequestTimingType.RequestRoutingStart;
var endingTimingType = HttpSysRequestTimingType.RequestRoutingEnd;
if (feature.TryGetElapsedTime(startingTimingType, endingTimingType, out var elapsed))
{
logger.LogInformation(
"Elapsed time {startingTimingType} to {endingTimingType}: {elapsed}",
startingTimingType,
endingTimingType,
elapsed);
}
else
{
logger.LogInformation(
"Elapsed time {startingTimingType} to {endingTimingType}:"
+ " not available for the current request.",
startingTimingType,
endingTimingType);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
用于支持 gRPC 的高级 HTTP/2 功能
HTTP.sys 中的其他 HTTP/2 功能支持 gRPC,包括支持响应尾部字段和发送重置帧。
使用 HTTP.sys 运行 gRPC 的要求:
- Windows 11 版本 22000 或更高版本,Windows Server 2022 版本 20348 或更高版本。
- TLS 1.2 或更高版本的连接。
Trailers
HTTP 尾部字段类似于 HTTP 标头字段,不同的是它们是在发送响应正文之后才发送的。 IIS 和 HTTP.sys 仅支持 HTTP/2 响应尾部字段。
if (httpContext.Response.SupportsTrailers())
{
httpContext.Response.DeclareTrailer("trailername");
// Write body
httpContext.Response.WriteAsync("Hello world");
httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}
在前面的示例代码中:
-
SupportsTrailers确保响应支持尾部字段。 -
DeclareTrailer将给定的尾部名称添加到Trailer响应头。 声明响应的尾部数据是可选的,但建议这样做。 如果要调用DeclareTrailer,则必须在发送响应标头之前进行此操作。 -
AppendTrailer追加尾部。
Reset
通过“Reset”,服务器可以使用指定的错误代码重置 HTTP/2 请求。 重置请求被视为中止。
var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);
前述代码示例中的 Reset 指定 INTERNAL_ERROR 错误代码。 有关 HTTP/2 错误代码的详细信息,请访问“HTTP/2 规范错误代码”部分。
Tracing
有关如何从 HTTP.sys 获取跟踪的信息,请参阅 HTTP.sys 可管理性方案。