sgcWebSockets 2026.7 关注的是生产环境中的运行。你现在可以把一个 WebSocket 应用铺开到多台服务器上,并让频道、发布/订阅和在线状态在所有服务器之间正常工作。频道可以记住它最近的消息,这样一个断开又回来的客户端就能拿到它错过的内容。客户端会以带抖动的指数退避方式重连,而不是齐刷刷地猛击服务器;发送队列可以设定上限,这样一个慢速消费者就不会耗尽服务器内存;HTTP 客户端还获得了一系列防护,用于应对会泄露凭据的重定向、被降级的 TLS 以及没有大小限制的响应。
除此之外,还有面向 Delphi 的 async / await 层、HTTP 服务器上的 gzip 和 deflate、新的 HTTP QUERY 方法、端到端加密的身份验证、MCP 客户端上的 OAuth2,以及一长串修复。本文是一次导览。每一节都链接到深入介绍该功能的文章。
跨多台服务器的集群
新的 TsgcWSCluster 组件把多台 sgcWebSockets 服务器连成一台逻辑服务器。在节点 A 上发布的消息可以送达连接在节点 B 上的订阅者,而在线状态返回的是整个集群的成员名单,而不只是本地节点的。有两种后端可选:内置的 mesh,节点之间直接通信,你无需额外安装任何东西;以及面向更大规模部署的 Redis Pub/Sub(企业版)。
uses
sgcWebSocket, sgcWebSocket_Protocols, sgcWebSocket_Cluster;
oCluster := TsgcWSCluster.Create(nil);
oCluster.EngineType := clusterMesh; // no extra infrastructure
oCluster.ClusterPort := 5410; // this node's mesh listener
oCluster.Peers.Add('192.168.1.101:5410'); // the other nodes
oCluster.Attach(oProtocol); // cluster this protocol's pub/sub
oCluster.Start;
了解更多:跨多节点扩展 WebSocket 服务器。
消息历史与重连恢复
sgc 协议服务器现在可以保留每个频道最近的 N 条消息,还可以选择带上存活时间。当客户端重连并重新订阅时,它会发送自己实际看到的最后一条消息的偏移量,服务器则会重放它离线期间发布的所有内容。除了你本来就会做的重新订阅之外,客户端代码无需任何改动,而且这整套机制在你启用之前都是关闭的。
oProtocol.History.Enabled := True;
oProtocol.History.Size := 1000; // last 1000 messages per channel
oProtocol.History.TTLSeconds := 3600; // optional: also expire after 1 hour
了解更多:消息历史与重连恢复。
async / await,以及一个真正会等待的 Connect
新的 sgcBase_AsyncAwait 单元为库带来了任务和 future。你可以 await 一个 HTTP 请求、一个 WebSocket 连接或一次 AI 聊天补全,而无需接线任何事件处理器,可以用 ThenProc 和 OnError 串联结果,也可以以真正中止底层请求的方式取消一个任务。
本着同样的精神,Connect 现在会阻塞直到连接完全建立,而不只是已经开始建立,Disconnect 也会等到套接字真正关闭。这消除了以往在快速重连时会咬人的一个竞态。当连接或发送失败时,原因可以从新的 LastError 属性中获得,而且还有一个 Connect 重载会直接把错误字符串返回给你,这样你无需订阅 OnError 就能诊断失败。
var
vError: string;
begin
if sgcWebSocketClient1.Connect(10000) then
sgcWebSocketClient1.WriteData('hello')
else
ShowMessage('Connect failed: ' + sgcWebSocketClient1.LastError);
// or get the reason back directly from the call
if not sgcWebSocketClient1.Connect(vError, 10000) then
ShowMessage('Connect failed: ' + vError);
end;
了解更多:Delphi 中的 async / await。
加固 HTTP 客户端
重定向是丢掉令牌最容易的方式。如果服务器用一个指向另一台主机的 302 来回应你已认证的请求,客户端会乐呵呵地把 Authorization 和 Cookie 请求头原样重放过去。2026.7 新增了 StripAuthOnCrossHostRedirect,用于在跨站重定向时丢弃这些请求头,以及 NoInsecureRedirect,用于拒绝把 HTTPS 降级为明文 HTTP 的重定向。
响应现在也可以设限了,MaxChunkSize 限制分块响应中单个块的大小,MaxResponseSize 限制总大小。RejectPublicSuffixCookies 会丢弃那些声称属于过于宽泛的域(例如 "com" 或 "co.uk")的 cookie。上传方面提供了 Expect: 100-continue,它会在发送大体积请求体之前先征得服务器同意,此外还支持分块请求体,用于流式上传你尚不知道大小的内容。
oHTTP.StripAuthOnCrossHostRedirect := True;
oHTTP.NoInsecureRedirect := True;
oHTTP.MaxResponseSize := 10 * 1024 * 1024; // 10 MB, 0 = unlimited
oHTTP.MaxChunkSize := 1024 * 1024; // 1 MB per chunk
oHTTP.RejectPublicSuffixCookies := True;
所有这些开关默认都是关闭的,而且都不需要你去碰底层的 HTTP 对象:它们同样发布在现成的 API 客户端上(AI/LLM、加密货币交易所、OAuth2、Google Cloud、WhatsApp、AWS SQS、WebPush)。重定向和大小防护同样存在于 HTTP/2 客户端上,而 HTTP/3 获得了响应大小限制。了解更多:加固 HTTP 客户端。
重试、退避与抖动
WatchDog 过去以固定间隔重连,这意味着一千个同时失去服务器的客户端会在同一瞬间一起回来。它现在支持指数退避,带有倍数、上限和随机抖动,这样整个客户端集群就会把自己摊开。固定间隔仍然是默认值,所以在你主动要求之前什么都不会变。
HTTP 客户端也获得了自己的重试策略:在可配置的一组状态码上重试,每次等待更久,并在服务器发送 Retry-After 提示时遵守它。OpenAI、Anthropic 和 Gemini 客户端也会使用它。
sgcWebSocketClient1.WatchDog.Backoff := wdbExponential;
sgcWebSocketClient1.WatchDog.BackoffMultiplier := 2.0; // double every attempt
sgcWebSocketClient1.WatchDog.MaxInterval := 60; // seconds, the ceiling
sgcWebSocketClient1.WatchDog.Jitter := 0.2; // up to 20% random spread
了解更多:指数退避、抖动与 Retry-After。
发送队列上的背压
当客户端读取的速度慢于你写入的速度时,排队的消息就会在服务器内存中堆积。你现在可以用 QueueOptions.MaxQueueSize 限制每个连接的待发消息数量,并选择达到上限时发生什么:丢弃最旧的消息、丢弃最新的消息,或者断开该连接。新的 OnSendBufferFull 事件会在任何消息被丢弃之前触发,因此你可以记录它、统计它,或者对某个你承受不起截断的连接否决这次丢弃。队列默认是无限制的。
oServer.QueueOptions.MaxQueueSize := 1000;
oServer.QueueOptions.OverflowPolicy := qopDropOldest; // or qopDropNewest, qopDisconnect
了解更多:面向慢速 WebSocket 客户端的发送队列限制。
HTTP 服务器上的 gzip 和 deflate
只要客户端声明了 Accept-Encoding,HTTP 服务器现在就可以压缩它的回复。它适用于从 DocumentRoot 提供的文件,也适用于你自己在 OnCommandGet 中构造的响应;它会跳过低于最小大小的正文以及压缩后不会变小的内容类型,并且在 HTTP.sys 服务器上同样可用。压缩默认关闭,目前只压缩 HTTP/1.1 的回复。
sgcWebSocketHTTPServer1.HTTPCompression.Enabled := True;
sgcWebSocketHTTPServer1.HTTPCompression.Level := 6; // 1..9
sgcWebSocketHTTPServer1.HTTPCompression.MinSize := 1024; // bytes
了解更多:HTTP 服务器上的 gzip 与 deflate 压缩。
HTTP QUERY 方法
QUERY 是一个新的 IETF HTTP 方法,它像 POST 一样在请求体中发送查询条件,却像 GET 一样保持安全且可缓存,因此你的查询不再被硬塞进一个有长度限制的 URL 里。2026.7 在 HTTP/1.x、HTTP/2、HTTP/3 和 REST 客户端上实现了它,服务器和代理也能处理它。
vResult := oClient.Query('https://api.example.org/contacts', oQuery);
了解更多:Delphi 中全新的 HTTP QUERY 方法。
E2EE 身份验证
端到端加密可以让载荷保持私密,但它本身并不能告诉你另一端是谁。中间的服务器或中继可以给每一方各发一份自己的密钥,然后读取全部内容。在 2026.7 中,每一方都可以用一个长期身份密钥为自己的加密密钥签名,另一方则验证该签名,这样悄无声息的密钥掉包就会被检测出来,而不是被接受。
它适用于一对一和群聊,还新增了用于批准或固定对端身份、以及在对端身份密钥发生变化时向你发出警告的事件;它默认关闭,并且与 2026.6 的对端完全向后兼容。
E2EE.E2EE_Options.Identity.Enabled := True;
E2EE.E2EE_Options.Identity.PrivateKey := LoadIdentityPrivateKey; // PEM
E2EE.E2EE_Options.Identity.PublicKey := LoadIdentityPublicKey; // PEM
E2EE.OnE2EEVerifyPeerIdentity := OnE2EEVerifyPeerIdentityEvent;
E2EE.OnE2EEKeyChange := OnE2EEKeyChangeEvent;
了解更多:E2EE 身份验证。
MCP 客户端的 OAuth2,以及 Identity Assertion 授权类型
MCP 客户端现在可以使用 OAuth2 认证,而不是静态的 API 密钥。它会自己获取令牌,在过期之前一直缓存并刷新它,而当 OAuth2 启用时,它的优先级高于 API 密钥。与此同时,OAuth2 客户端新增了一种授权类型,即 Identity Assertion Authorization Grant,它可以把一个域中的身份传递到另一个域:客户端会替你完成整个多步骤交换,并触发事件让你能跟踪每一步。
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.Enabled := True;
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.GrantType := auth2ClientCredentials;
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.TokenURL := 'https://auth.example.com/oauth2/token';
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.ClientId := 'YOUR_CLIENT_ID';
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.ClientSecret := 'YOUR_CLIENT_SECRET';
了解更多:MCP 客户端的 OAuth2。
加密货币行情:重新订阅与限流
直到现在,当一个行情套接字断开而 WatchDog 把它拉回来之后,套接字是通了,但在你自己重放每一个订阅之前,你其实什么都没订阅。交易所客户端现在可以替你做这件事:设置 Resubscribe := True,你的数据流就会在重连后被恢复。它覆盖 Binance、Kraken、Coinbase 以及另外大约十四家交易所,还有 XTB 基于会话的行情。它默认为 False。
REST API 客户端获得了一个可选的客户端限流器,这样一波突发请求就不会让你被交易所临时封禁。限制你在一个时间窗口内发送的请求数量,并选择超额的请求是等待还是被拒绝。默认关闭。
oBinance.RateLimit.Enabled := True;
oBinance.RateLimit.IntervalMs := 60000; // one minute window
oBinance.RateLimit.MaxRequests := 1000;
oBinance.RateLimit.Behavior := rlbWait;
了解更多:重新订阅与客户端限流器。
较小的新增内容
- TLS 预设。每个 TLS 选项对象现在都发布了一个
Preset属性。设置TLSOptions.Preset := tlspSecureDefaults只需一行就能打开证书验证、TLS 1.2 或更高版本以及主机名检查。默认值tlspCustom不会改动你当前的设置。 - 自定义 HTTP 会话类。在启动 HTTP 服务器之前,把你自己的
TIdHTTPSession派生类赋给服务器的SessionClass,你就可以在会话中存放自己的数据,而会话 id、cookie、超时和清理机制仍与以往完全一样地工作。如果你需要完全掌控会话存放在哪里,还可以赋值你自己的SessionList。 - RFC 2253 证书辅助函数。新函数可以把证书的主体和签发者读取为标准的 RFC 2253 可分辨名称字符串。
- WinHTTP WebSocket 客户端。它现在像标准客户端一样支持 token/bearer 和 URL 登录,暴露了
OnHandshake事件,让你可以给连接请求添加自己的请求头,还能写入日志文件,记录连接、断开以及收发的每一条文本和二进制消息。OAuth2、JWT 和会话登录在那里仍然不可用,因为它使用的是 Windows 内置的网络栈,并不包含 Indy。
修复与加固
2026.7 带来了一长串修复。与其把它们全部重复一遍,不如看看它们合起来意味着什么。
内存安全与解析器加固。修复了越界读取问题,涉及 MQTT 5 客户端(broker 声称的数据量多于它实际发送的量)、AMQP 1.0 客户端(UUID 解码)、STUN/TURN 解析器(包括一个死循环和 IPv6 地址)、WebRTC SCTP 数据通道以及原始 TCP 帧扫描器。UDP 客户端和服务器(包括 DTLS)在断开时不会再重复释放套接字或让它悬空。在行为异常的对端本可无限制增长内存的地方,加入了内部上限:MQTT 待发消息队列、sgc 协议的每连接订阅数、WAMP 服务器的待处理调用、分块响应的 trailer 行,以及 AMQP 字段表的嵌套深度。
HTTP/2。一个解压后大小上限(默认 64 MB)堵住了 "zip 炸弹" 响应导致的内存耗尽漏洞,响应大小限制不再能被响应的最后一部分绕过,而失败的请求现在会立即失败,而不是把整个超时耗完。
加密与随机数。WebAuthn 服务器、OAuth2 授权服务器以及内置的 HTTP 会话 id 现在使用密码学安全的随机数生成器,挑战值一次性使用,机密以常量时间进行比较(客户端密钥、JWT 签名、HTTP API Basic 密码)。签名有效但声明有误的 JWT 现在会被拒绝,而不是被接受。启用 OpenSSL 的 StrictVerify 后,证书还会针对主机名进行校验,因此一张为其他主机签发的有效证书会被拒绝。连接到 IP 地址的情形以及现有设置不受影响。
Server-Sent Events。一个流式响应如果在一次读取中送来多个事件,或者一个事件被拆分在两次读取中,除第一个之外的内容都会丢失。此问题已修复,这也恢复了 AI/LLM 客户端逐 token 的流式输出。OpenAI 流式聊天此前还漏设了 stream 标志,现在它会像其他提供方一样流式输出。
交易所客户端。Kraken 的请求 id 现在严格递增,BitMEX 以秒而不是毫秒发送其过期时间,MEXC 对它实际发送的编码参数进行签名,Cryptorobotics 在按哈希调用中不再交换两个值,Deribit 会在登录令牌过期前刷新它,而 Forex 客户端会报告它以往在读取账户 id 时吞掉的错误。
Lazarus 与 Free Pascal。三处编译修复:JSON 单元的接口现在按平台使用正确的调用约定(此前在 Linux 上无法编译)、Forex 客户端不再调用仅限 Delphi 的函数来读取数字格式,以及后量子密钥交换单元不再依赖 size_t。
history.txt 中还有更多内容,包括 gRPC 客户端(并发调用可能收到彼此的回复,且发送失败被报告为成功)、OpenAPI 服务器(规范加载现在是线程安全的,而且你的处理器不会再在内部锁被持有时运行)、每次登录失败都会造成的服务器连接与套接字泄漏、对没有 "message" 字段的 OpenAI 回复(例如来自 Ollama 和 LM Studio 的回复)导致的崩溃、WinHTTP 客户端上修复的 WriteAndWaitData,以及 HTTP 客户端日志中的机密脱敏,这样启用日志不会再把令牌以明文写到磁盘上。
.NET 版本
sgcWebSockets .NET 2026.7 的重点是 HTTP 客户端。它提供了与 Delphi 版本相同的一整套防护:跨站重定向时剥离凭据、阻止 HTTPS 到 HTTP 的降级、单块与总响应大小上限、公共后缀 cookie 拒绝、Expect: 100-continue 以及分块请求体。这些功能在 HTTP 客户端组件和现成的 API 客户端上均可用(AI/LLM 客户端、OAuth2、Google Cloud、WhatsApp、AWS SQS、WebPush),同样的重定向与大小防护也存在于 HTTP/2 客户端上。重定向处理和 cookie 过期的修复也一并包含在内。所有功能默认关闭。
升级
对现有的 2026.x 项目而言,2026.7 是一次即插即用的升级。本次发布中的每一项新功能默认都是关闭的:集群、消息历史、退避、发送队列上限、HTTP 压缩、客户端防护、E2EE 身份验证以及交易所重新订阅,全都必须显式打开,因此安装新版本在你主动启用之前不会改变任何行为。
拥有有效订阅的客户可以从客户专区下载新版本,或从 esegece.com/products/websockets/download 下载。
有疑问、建议,或者需要迁移方面的帮助?联系我们。回复你的将是编写这些代码的人。
