sgcQUIC 五分钟上手

基于 OpenSSL 内置 QUIC 引擎的原生 Object Pascal QUIC 和 HTTP/3。共有四个组件。最快跑起来的路径是 HTTP/3 客户端,因此本页发出一个请求,读取状态码,并明确说明您需要哪个版本的 OpenSSL。

QUIC RFC 9000 和 HTTP/3 RFC 9114
客户端需要 OpenSSL 3.2 及更高版本
All-Access 版本

第一个请求所需的内容

一个组件,一个 URL,以及放在可执行文件旁边的两个 OpenSSL 库。

组件

SGC QUIC 组件面板页上的 TsgcHTTP3Client,声明在 sgcQUIC.pas 中。该页面还包含 TsgcQUICClient、TsgcQUICServer 和 TsgcHTTP3Server。

单元

组件使用 sgcQUIC。TsgcHTTP3Response 需要添加 sgcHTTP3_Classes,如果要处理 Alt-Svc 事件,则还需要 sgcHTTP_AltSvc。

调用

Get(aURL) 以 string 形式返回正文,失败时抛出异常。状态码和标头通过 OnResponse 单独送达。

OpenSSL 要求

客户端需要 OpenSSL 3.2 或更高版本中的 QUIC API,或者 quictls 构建。服务器需要 3.5 或更高版本,因为它调用了仅存在于该版本中的 API。请把 libcrypto-3.dll 和 libssl-3.dll 放在可执行文件旁边,每个演示文件夹都是这样做的。

要求与版本

版本列给出的是控制代码的定义,以及它在 Source/sgcVer.inc 中所在的行号。

项目 值
IDE Delphi 7 到 RAD Studio 13,以及 C++Builder 2007 到 13。没有单独的 sgcQUIC 下载:这些组件包含在 sgcWebSockets 包组中。
uses 子句 sgcQUIC,响应对象需要 sgcHTTP3_Classes,Alt-Svc 类型需要 sgcHTTP_AltSvc。
包定义 SGC_PACK_QUIC 定义在第 872 行,位于从第 870 行延伸到第 874 行的 {$IFDEF SGC_EDT_ALL} 块内。因此是 All-Access。
功能定义 位于第 894 行到第 899 行的 {$IFDEF SGC_PACK_QUIC} 块内:SGC_QUIC 在第 896 行,SGC_HTTP3 在第 897 行,SGC_WEBTRANSPORT 在第 898 行。这三者都位于第 895 行的 {$IFDEF SGC_INDY_LIB} 之内,因此没有自定义 Indy 库的构建一个都得不到。
OpenSSL,客户端 3.2 或更高版本,或者 quictls 构建。库自己就是这样说明的:QUIC 不可用时抛出的错误信息为 QUIC is not available. Requires quictls/openssl or OpenSSL 3.2+。
OpenSSL,服务器 3.5 或更高版本。QUIC 服务器会调用 SSL_new_listener,缺少它时抛出的错误信息为 QUIC Server requires OpenSSL 3.5 or later。不使用 msquic,也不需要它。
平台 sgcQUIC.pas、sgcQUIC_Client.pas、sgcHTTP3_Client.pas 和 sgcHTTP3_Server.pas 上都没有单元级平台保护,并且这四个组件都使用 ComponentPlatforms(0) 注册。服务器单元按平台选择套接字 API,同时包含 Windows 和 POSIX 两个分支。

不确定运行时是否存在该引擎?调用 IsOpenSSL_QUIC_Available,它会返回您加载的 OpenSSL 是否提供 QUIC 客户端方法。随包附带的 QUIC 客户端演示正是出于这个原因,在启动时记录了这一结果。

安装并找到组件面板页

没有单独的 sgcQUIC 安装程序。这些组件随 sgcWebSockets 一起提供,在版本启用它们之后就会出现。

1. 解压

将 sgcWebSockets 下载文件解压到一个文件夹,下文称之为 {$DIR}。

2. 库路径

依次选择 Tools、Options、Library。添加 {$DIR}\source 以及与您的 IDE 对应的 lib 文件夹,例如 {$DIR}\libD13\$(Platform)。

3. 构建包

在 {$DIR}\Packages\ 下,打开与您的 IDE 版本对应的包组。先编译运行时 .dpk,再安装设计时 dcl 包。没有专用于 QUIC 的包。

4. 检查组件面板

会出现一个名为 SGC QUIC 的页面,包含 TsgcQUICClient、TsgcQUICServer、TsgcHTTP3Client 和 TsgcHTTP3Server。如果缺少该页面,说明构建不是 All-Access,因为 SGC_PACK_QUIC 只在该块内的第 872 行定义。

5. 把 OpenSSL 放在 exe 旁边

将 libcrypto-3.dll 和 libssl-3.dll 复制到可执行文件旁边,客户端需要 3.2 或更高版本,服务器需要 3.5 或更高版本。Demos\22.QUIC_Protocol 下的每个文件夹都附带它们,因此您可以从那里复制。

一个 HTTP/3 请求

创建客户端,连接三个事件,调用 Get。回复以字符串形式返回,状态码通过 OnResponse 送达。

FHTTP3Client.pas
uses
  Classes, SysUtils,
  // sgc
  sgcQUIC, sgcHTTP3_Classes;

procedure TfrmHTTP3Client.FormCreate(Sender: TObject);
begin
  FClient := TsgcHTTP3Client.Create(nil);
  FClient.OnConnect := OnH3Connect;
  FClient.OnError := OnH3Error;
  FClient.OnResponse := OnH3Response;
  FClient.TLSOptions.VerifyCertificate := True;
  FClient.ConnectTimeout := 10000;
  FClient.ReadTimeout := 30000;
  FClient.UserAgent := 'sgcWebSockets/HTTP3Client';
end;

procedure TfrmHTTP3Client.btnGetClick(Sender: TObject);
var
  vResult: string;
begin
  try
    // the target comes from the URL, because Host and Port
    // are read-only on this component
    vResult := FClient.Get('https://www.google.com/');
    memoBody.Lines.Text := vResult;
    DoLog('Response received: ' + IntToStr(Length(vResult)) + ' bytes');
  except
    on E: Exception do
      DoLog('Error: ' + E.Message);
  end;
end;

Post、Put 和 Delete 的形式相同,并且每个都有流重载,用于不想放在字符串中的正文。如果想把两者分开,Connect(const aHost: string; aPort: Integer = 443) 会在第一个请求之前先打开连接。

FHTTP3Client.pas
// OnConnect and OnDisconnect are plain TNotifyEvent on this
// component: one parameter, no connection object.
procedure TfrmHTTP3Client.OnH3Connect(Sender: TObject);
begin
  DoLog('Connected to ' + FClient.Host + ':' + IntToStr(FClient.Port));
end;

procedure TfrmHTTP3Client.OnH3Error(Sender: TObject; const aError: string);
begin
  DoLog('Error: ' + aError);
end;

procedure TfrmHTTP3Client.OnH3Response(Sender: TObject;
  const aResponse: TsgcHTTP3Response);
begin
  DoLog('Status: ' + IntToStr(aResponse.StatusCode));
  memoHeaders.Lines.Assign(aResponse.Headers);
end;

在 OnConnect 内读取 FClient.Host 和 FClient.Port,正是这两个属性的用途。它们报告连接情况,而不是配置连接。

FQUICClient.pas
uses
  Classes, SysUtils,
  // sgc
  sgcIdSSLOpenSSLHeaders;

procedure TfrmQUICClient.FormCreate(Sender: TObject);
begin
  DoLog('OpenSSL QUIC Support:');
  DoLog('  quictls API: ' +
    BoolToStr(IsOpenSSL_QUIC_TLS_Available, True));
  DoLog('  Builtin QUIC (3.2+): ' +
    BoolToStr(IsOpenSSL_QUIC_Available, True));
end;

在做其他任何事情之前,先运行一次。如果两者都返回 false,说明可执行文件旁边的 OpenSSL 不支持 QUIC,此后每一次连接失败都是这一个事实的症状,而不是网络的问题。

前两个选项卡来自随包附带的演示 Demos\22.QUIC_Protocol\03.HTTP3_Client\FHTTP3Client.pas,其中的窗体控件已替换为字面量。第三个是来自 01.QUIC_Client\FQUICClient.pas 的运行时可用性检查。该文件夹中有六个 QUIC 演示,包括一对 WebTransport 演示。

读取状态码,而不仅仅是正文

Get 返回正文。响应对象携带其他所有内容,并通过自己的事件送达。

返回值

Get 以 string 形式返回响应正文,失败时抛出异常,因此演示把它包在 try except 中。长度符合预期的正文是第一个证明。

OnResponse

procedure(Sender: TObject; const aResponse: TsgcHTTP3Response)。StatusCode 是您真正想要的数字,Headers 是一个 TStringList,GetDataAsString 可以从响应对象中再次获取正文。

OnConnect

一个普通的 TNotifyEvent。只要它触发,就说明 QUIC 协商成功并且 HTTP/3 会话已打开,这正是首次运行时最容易失败的部分。

在责怪代码之前

IsOpenSSL_QUIC_Available 回答了值得最先提出的唯一问题。QUIC 还运行在 UDP 443 上,允许 TCP 443 的网络不一定允许它。

第一次通常会出什么问题

六个问题几乎涵盖了所有失败的第一个请求。

无法给 Host 或 Port 赋值

它们在 TsgcHTTP3Client 上是只读的,声明为 property Host: string read FHost 和 property Port: Integer read FPort。它们报告客户端连接到哪里。要选择目标,请把完整的 URL 传给 Get,或调用 Connect(aHost, aPort)。

QUIC 不可用

您加载的 OpenSSL 太旧,或者构建时没有包含 QUIC。客户端需要 3.2 或更高版本,或者 quictls。在责怪网络之前,请在运行时用 IsOpenSSL_QUIC_Available 检查。

服务器无法启动

QUIC 服务器需要 OpenSSL 3.5 或更高版本,因为它调用了 SSL_new_listener。3.2 构建对客户端足够,对服务器则不够,错误信息中明确说明了这一点。

OnConnect 的参数个数不对

该组件上的 OnConnect 和 OnDisconnect 是普通的 TNotifyEvent,因此处理程序只接受 Sender: TObject。与 WebSocket 组件不同,它们不会给您传递连接对象。

UDP 被阻止

QUIC 运行在 UDP 的 443 端口上,许多企业网络允许 TCP 443 却丢弃 UDP 443。如果浏览器能通过 HTTP/3 访问该主机而您的应用程序不能,请先怀疑防火墙,再怀疑代码。

缺少组件面板页

SGC_PACK_QUIC 只在 All-Access 块内的第 872 行定义。它还要求 SGC_INDY_LIB,因为第 894 行到第 899 行的整个包块都位于该保护块之内。

第一个请求之后

四个方向,都在同一个包内。

运行 HTTP/3 服务器

TsgcHTTP3Server 直接通过 QUIC 提供 HTTP/3 服务。请记住服务器端对 OpenSSL 3.5 的最低版本要求。

HTTP/3 服务器组件

原始 QUIC,不使用 HTTP

TsgcQUICClient 和 TsgcQUICServer 提供没有 HTTP/3 层的 QUIC 流,适用于需要多路复用且不希望出现队头阻塞的自定义协议。

QUIC 客户端和 QUIC 服务器

WebTransport

通过 HTTP/3 与浏览器之间的双向流和数据报,由第 898 行的 SGC_WEBTRANSPORT 控制。附带两个演示。

sgcQUIC 功能

从 HTTP/2 发现 HTTP/3

服务器通过 Alt-Svc 标头声明支持 HTTP/3。处理 OnAltSvc,当源站提供 QUIC 时,您就可以把现有连接升级到 QUIC。

HTTP/2 客户端

参考、演示和文档

演示项目包含在下载包内,位于 Demos\22.QUIC_Protocol 下,共有六个。

HTTP/3 客户端组件 TsgcHTTP3Client 公开的内容,逐个属性说明。
HTTP/3 服务器组件 服务器端,包括对 OpenSSL 3.5 的要求。
QUIC 客户端组件 没有 HTTP/3 层的原始 QUIC 流。
sgcQUIC 功能 QPACK、0-RTT、连接迁移、WebTransport 等。
下载试用版 每个 IDE 版本一个安装程序,已内置 QUIC 组件。
在线帮助 自动生成的参考,始终与当前版本保持同步。

相关阅读:QUIC 客户端和服务器组件以及 HTTP/3 组件。如果您正在选择传输方式,实时传输指南对它们进行了比较。每个产品都有自己的快速入门,列在入门页面上。

sgcQUIC 快速入门常见问题

SGC QUIC 组件面板页上的 TsgcHTTP3Client,来自单元 sgcQUIC。TsgcHTTP3Response 是 OnResponse 的参数类型,需要添加 sgcHTTP3_Classes;如果要处理 OnAltSvc,则需要 sgcHTTP_AltSvc。该组件面板页还包含 TsgcQUICClient、TsgcQUICServer 和 TsgcHTTP3Server。
这取决于您构建的是哪一端。客户端需要 OpenSSL 3.2 中新增的 QUIC API,或者 quictls 构建,库在抛出的信息中就是这样说明的:QUIC is not available. Requires quictls/openssl or OpenSSL 3.2+。服务器需要 3.5 或更高版本,因为它调用了 SSL_new_listener,其错误信息中明确指出了该版本。请把 libcrypto-3.dll 和 libssl-3.dll 放在可执行文件旁边。不使用 msquic。
因为它们是只读的。TsgcHTTP3Client 将它们声明为 property Host: string read FHost 和 property Port: Integer read FPort,因此它们报告当前连接,而不是配置连接。请把完整的 URL 传给 Get、Post、Put 或 Delete,或者先调用 Connect(const aHost: string; aPort: Integer = 443)。
一个普通的 TNotifyEvent,即 procedure(Sender: TObject)。OnDisconnect 也是如此。这与 WebSocket 组件不同,后者的事件会传给您一个 TsgcWSConnection,这是首次编译出错的常见原因。OnResponse 是 procedure(Sender: TObject; const aResponse: TsgcHTTP3Response),OnError 是 procedure(Sender: TObject; const aError: string)。
从 OnResponse 上的响应对象中读取。TsgcHTTP3Response 提供 StatusCode、作为 TStringList 的 Headers,以及用于获取正文的 GetDataAsString。Get 方法本身只以字符串形式返回正文,这就是演示同时连接 OnResponse 的原因。
SGC_PACK_QUIC 定义在 sgcVer.inc 的第 872 行,位于从第 870 行延伸到第 874 行的 {$IFDEF SGC_EDT_ALL} 块内。因此是 All-Access。包块本身(第 894 行到第 899 行)也位于 {$IFDEF SGC_INDY_LIB} 之内,因此构建中还必须包含自定义 Indy 库。在该块内,SGC_QUIC 在第 896 行,SGC_HTTP3 在第 897 行,SGC_WEBTRANSPORT 在第 898 行。
没有。试用版安装程序按 IDE 版本提供,并且已经包含 QUIC 和 HTTP/3 组件,也没有专用于 QUIC 的包文件。安装 sgcWebSockets,当版本启用时,SGC QUIC 组件面板页就会出现。
可以,而且您应该这样做。IsOpenSSL_QUIC_Available 返回已加载的 OpenSSL 是否提供 QUIC 客户端方法,IsOpenSSL_QUIC_TLS_Available 对 QUIC TLS 回调执行同样的检查。随包附带的 QUIC 客户端演示在启动时会把两者都写入日志,这样一个莫名其妙的连接失败就变成了一行答案。
超值之选:All-AccesseSeGeCe 全部产品,含高级支持,每年 €1,059 起。
查看 All-Access 价格

准备好在 Delphi 中尝试 HTTP/3 了吗?

下载试用版,并针对真实的源站运行 HTTP/3 客户端演示。