Cadente
本页由英文自动翻译。 阅读原文
Cadente 是为 Sisk 提供的实验性托管 HTTP/1.1 监听器实现。它作为默认的 System.Net.HttpListener 的替代品,提供更大的控制力和灵活性,尤其在非 Windows 平台上。
概述 #
默认情况下,Sisk 使用 HttpListener(来自 System.Net)作为底层 HTTP 服务器引擎。虽然 HttpListener 在 Windows 上(使用内核模式的 HTTP.sys 驱动)稳定且性能良好,但其在 Linux 和 macOS 上的实现是托管的,历史上存在一些限制,例如缺乏原生 SSL 支持(需要使用 Nginx 等反向代理)以及性能特性各异。
Cadente 旨在通过提供一个用 C# 编写的完全托管的 HTTP/1.1 服务器来解决这些问题。其主要目标包括:
- Native SSL Support: 在所有平台上工作,无需外部代理或复杂配置。
- Cross-Platform Consistency: 在 Windows、Linux 和 macOS 上表现一致。
- Performance: 旨在成为托管
HttpListener的高性能替代方案。 - Independence: 与
System.Net.HttpListener解耦,使 Sisk 免受该组件未来可能被弃用或缺乏维护的影响。
警告
实验状态
Cadente 目前处于实验阶段(Beta)。尚不建议在关键生产环境中使用。API 和行为可能会更改。
安装 #
Cadente 以独立的包形式提供。要在 Sisk 中使用它,需要 Sisk.Cadente.CoreEngine 包。
dotnet add package Sisk.Cadente.CoreEngineSisk.Cadente 和 Sisk.Cadente.CoreEngine 目标为 .NET 9 和 .NET 10。它们不能在目标为 .NET 8 的项目中使用,尽管 Sisk.HttpServer 支持 .NET 8。
在 Sisk 中使用 #
要将 Cadente 作为 Sisk 应用的 HTTP 引擎,需要将 HttpServer 配置为使用 CadenteHttpServerEngine 而非默认引擎。
CadenteHttpServerEngine 将 Cadente 的 HttpHost 适配为 Sisk 所需的 HttpServerEngine 抽象。
using Sisk.Core.Http;
using Sisk.Cadente.CoreEngine;
using var host = HttpServer.CreateBuilder()
.UseEngine<CadenteHttpServerEngine>()
.UseSsl(certificate: CertificateHelper.CreateTrustedDevelopmentCertificate("localhost"))
.Build();
await host.StartAsync();当监听主机配置了 SSL 时,HttpServer.ListeningPrefixes 会使用 https 方案报告其地址。如果客户端向配置了 SSL 的端口发送普通 HTTP,Cadente 会返回 301 Moved Permanently 重定向到同一主机和路径的 https 地址。
高级配置 #
可以通过向 CadenteHttpServerEngine 构造函数传递设置操作来自定义底层的 HttpHost 实例。这对于配置超时或其他底层设置非常有用。
using var engine = new CadenteHttpServerEngine(host =>
{
// 配置客户端读/写超时
host.TimeoutManager.ClientReadTimeout = TimeSpan.FromSeconds(30);
host.TimeoutManager.ClientWriteTimeout = TimeSpan.FromSeconds(30);
});独立使用 #
虽然主要为 Sisk 设计,Cadente 也可以作为独立的 HTTP 服务器使用(类似于 HttpListener)。
using Sisk.Cadente;
var host = new HttpHost(15000)
{
Handler = new MyHostHandler()
};
host.Start();
Thread.Sleep(-1);
class MyHostHandler : HttpHostHandler
{
public override async Task OnContextCreatedAsync(HttpHost host, HttpHostContext context)
{
context.Response.StatusCode = 200;
using var stream = await context.Response.GetResponseStreamAsync(chunked: true);
using var writer = new StreamWriter(stream);
await writer.WriteLineAsync("Hello, world!");
}
}当响应体较小且已在内存中时,WriteInlineContent 和 WriteInlineContentAsync 会在一次操作中写入头部和主体。响应必须包含 Content-Length 头部:
byte[] body = "Hello, world!"u8.ToArray();
context.Response.StatusCode = 200;
context.Response.Headers.Set(new HttpHeader("Content-Length", body.Length.ToString()));
await context.Response.WriteInlineContentAsync(body);请求验证 #
Cadente 在请求到达处理程序之前会验证请求的框架。自 1.7 版本起,它:
- 支持在 keep-alive 连接上的流水线请求;
- 拒绝不是有效 HTTP 令牌的请求方法以及包含可见 ASCII 范围之外字节(
%x21-7E)的请求目标; - 拒绝
Transfer-Encoding不是单一chunked值的请求,以及具有冲突Content-Length头的请求; - 当请求行和头部超过 8 KB 时,返回
431 Request Header Fields Too Large并关闭连接。
无效请求会返回错误并关闭连接,且不会调用处理程序。