Cloudflare Workers 兼容性标志实战:启用 WebSocket Compression(permessage-deflate)
【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docs
本指南围绕 Cloudflare Workers 的兼容性标志web_socket_compression展开,解析 Workers 运行时从"剥离/忽略Sec-WebSocket-Extensions头"到"完整遵循 WebSocket 压缩 RFC"的演进过程,并给出在 Wrangler 配置文件 中启用该标志、在new WebSocket(url)与fetch()两种连接方式下协商permessage-deflate压缩的完整做法。读完你将掌握该标志的生效机制、RFC 7692 压缩参数的配置方式,以及它与其它 WebSocket 兼容性标志的协同关系。
兼容性标志的定位:为什么需要它
Cloudflare Workers 运行时通过"兼容性日期 + 兼容性标志"机制控制行为变更。每当运行时要改变某个既有 API 的默认行为时,默认保持旧行为,只有到达特定兼容性日期、或显式开启对应标志后才切换到新行为。这一点在 Wrangler 配置文档 中有明确说明:compatibility_flags是一个字符串数组,用于"启用来自即将到来的 Workers 运行时特性的标志,通常与compatibility_date一起使用"。
web_socket_compression正是这类行为切换的一个典型例子,其 frontmatter 元数据(记录于 web-socket-compression.md 文件头部)定义了该标志的完整生命周期:
| 字段 | 值 | 含义 |
|---|---|---|
name | WebSocket Compression | 标志的人类可读名称 |
sort_date | 2023-08-05 | 用于排序的日期(通常为公开/预告时间) |
enable_date | 2023-08-15 | 到达该兼容性日期后标志自动生效 |
enable_flag | web_socket_compression | 手动开启时使用的标志名 |
disable_flag | no_web_socket_compression | 手动关闭(回退旧行为)时使用的标志名 |
从仓库的 兼容性标志 Schema 可以看到,name、enable_flag、disable_flag、sort_date是这类标志文档共用的结构化字段,enable_date与experimental可选。这意味着该标志既可以"随日期自动开启",也可以由开发者按需手动启用或禁用,便于在迁移期精确控制行为。
背景:Workers 运行时与 WebSocket 压缩的历史行为
web_socket_compression标志的存在,根源于 Workers 运行时在 WebSocket 压缩支持上的一段历史:
- 初版实现不含压缩:Workers 运行时最初发布 WebSocket 实现时,并不支持 WebSocket 压缩(即 RFC 7692 定义的
permessage-deflate扩展)。 - 头部被剥离或忽略:历史上,运行时在处理 WebSocket 握手时会剥离或忽略
Sec-WebSocket-Extensions请求头,即使客户端显式请求压缩也不会被响应。 - 现状:运行时现在已经具备完整遵守 WebSocket Compression RFC 的能力,可以基于
Sec-WebSocket-Extensions头的协商结果,在**入站(inbound)和出站(outbound)**WebSocket 连接上实际使用压缩。
为什么默认不直接开启?关键原因在于大量存量客户端今天就在向 Workers 发送Sec-WebSocket-Extensions: permessage-deflate——尤其是浏览器中new WebSocket(url)会自动附带该头。如果运行时突然从"忽略该头"变成"响应压缩",可能改变消息帧的编码方式,进而影响依赖原始行为的上游应用。因此,在标志缺席时运行时继续保持历史行为;只有标志存在(无论是到达enable_date自动生效,还是开发者显式开启)时才启用压缩能力。这种"默认保守、显式开启"的兼容性策略,正是为了不让行为变更破坏已有 Worker。
启用方式:Wrangler 配置中的两种途径
途径一:更新兼容性日期
将 Wrangler 配置中的compatibility_date设置到 2023-08-15 或之后,该标志即随日期自动生效。这是绝大多数新项目采用的默认路径,因为你只需保持日期最新即可获得压缩能力。
途径二:显式指定兼容性标志
在compatibility_flags数组中显式列出web_socket_compression,可在兼容性日期尚未到达时提前启用:
{ "name": "my-worker", "main": "src/index.js", "compatibility_date": "2023-06-01", "compatibility_flags": ["web_socket_compression"] }回退:禁用压缩
如果在日期已过、标志自动生效之后希望回退到旧行为,可将disable_flag加入配置:
{ "compatibility_flags": ["no_web_socket_compression"] }no_web_socket_compression会显式恢复"忽略/剥离Sec-WebSocket-Extensions"的历史行为,适用于那些对消息帧编码有严格要求、暂时不希望启用压缩的存量服务。注意:enable_flag与disable_flag是互斥的,不应同时出现在同一份配置中。按 Wrangler 配置文档 的约定,compatibility_flags是string[]类型、可选字段,因此你可以按需自由组合多个 WebSocket 相关标志(见下文"与其他 WebSocket 标志协同"一节)。
压缩协商的两种连接方式
启用标志后,运行时会在握手阶段依据Sec-WebSocket-Extensions头协商是否使用permessage-deflate压缩。根据 Worker 中建立 WebSocket 连接的方式不同,协商过程分为两种:
方式一:new WebSocket(url)(客户端式)
与浏览器行为一致,在 Worker 中调用new WebSocket(url)会自动在握手请求中附带Sec-WebSocket-Extensions: permessage-deflate头。运行时收到该请求后,会在标志生效的前提下响应压缩扩展,从而对这条出站连接启用压缩:
// 自动协商:无需手动设置任何头 const ws = new WebSocket("wss://example.com"); ws.addEventListener("open", () => { ws.send("hello"); });这种方式最接近浏览器开发者的直觉——代码无需任何改动即可获得压缩能力(前提是标志生效)。
方式二:fetch()+Upgrade: websocket(服务器式)
如果使用非标准的fetch()API 获取 WebSocket(即先发起带Upgrade: websocket的 HTTP 请求,再取出resp.webSocket),握手头不会像new WebSocket那样自动填充。此时需要手动携带Sec-WebSocket-Extensions头,值为permessage-deflate,并可附带 RFC 7692 第 7 节定义的一个或多个压缩参数:
const resp = await fetch("https://example.com", { headers: { Upgrade: "websocket", "Sec-WebSocket-Extensions": "permessage-deflate; server_no_context_takeover; client_max_window_bits=10", }, }); if (!resp.webSocket) { throw new Error("WebSocket handshake not accepted"); } const ws = resp.webSocket; ws.accept(); ws.addEventListener("message", (event) => { // 服务端已解压的消息 console.log(event.data); });fetch()方式常用于 Worker 充当 WebSocket 代理(Proxy)或网关的场景,通过显式控制握手头来精确决定是否启用压缩。需要说明的是,fetch()在该仓库的 WebSocket 运行时 API 文档 中被描述为获取 WebSocket 的非标准途径——标准途径始终是new WebSocket()。
RFC 7692 压缩参数说明
文档明确允许在使用fetch()方式时附带 RFC 7692 第 7 节定义的任意压缩参数。以下是该节定义的核心参数及其含义(在握手请求中按需组合):
| 参数 | 含义 | 典型用法 |
|---|---|---|
server_no_context_takeover | 服务端每个消息都重置压缩上下文(不跨消息保留字典) | 降低内存占用,换取略微更高的压缩率损失 |
client_no_context_takeover | 客户端每个消息都重置压缩上下文 | 同上,作用于客户端方向 |
server_max_window_bits=<n> | 限制服务端使用的 LZ77 滑动窗口大小(8–15) | 数值越小,服务端内存占用越低 |
client_max_window_bits=<n> | 限制客户端使用的 LZ77 滑动窗口大小(8–15) | 数值越小,客户端内存占用越低 |
如果你不需要精细控制,直接发送Sec-WebSocket-Extensions: permessage-deflate即可,运行时与对端会就默认窗口大小与上下文策略完成协商。
与其他 WebSocket 兼容性标志的协同
web_socket_compression并不是唯一的 WebSocket 行为切换标志。在仓库的 compatibility-flags 目录 中,还维护着若干聚焦不同方面的姊妹标志,实践中常与压缩标志一起评估:
websocket_standard_binary_type(记录于 websocket-standard-binary-type.md):控制WebSocket.binaryType的默认值。开启后默认"blob",二进制帧以Blob送达,符合 WebSocket 规范与浏览器行为;关闭时默认"arraybuffer",保持运行时历史行为。该标志不影响 Durable Object 的 hibernatable WebSocket 处理器。web_socket_auto_reply_to_close(记录于 web-socket-auto-reply-to-close.md):服务端发送 Close 帧后,运行时自动回发对等 Close 帧并将readyState置为CLOSED,与 WebSocket 规范对齐。同时accept({ allowHalfOpen: true })可恢复半开行为,便于实现 WebSocket 代理场景的优雅关闭协调。websocket_close_reason_byte_limit(记录于 websocket-close-reason-byte-limit.md):开启后,WebSocket.close()的reason参数按 UTF-8 编码超过 123 字节时抛出SyntaxErrorDOMException,符合 WHATWG 规范与 RFC 6455 第 5.5 节的要求;此前 Workers 允许任意长度的关闭原因。
这些标志与压缩标志一样遵循相同的 schema 与启用/禁用机制(enable_flag/disable_flag),因此可以在compatibility_flags数组中一并管理,例如:
{ "compatibility_flags": [ "web_socket_compression", "websocket_standard_binary_type", "web_socket_auto_reply_to_close" ] }在升级兼容性日期时,建议同时审阅这些标志的enable_date,评估行为变更对存量代码的影响,避免某一项默认行为切换造成意外。
验证与注意事项
验证压缩是否生效:启用标志后,可通过抓取握手响应中的
Sec-WebSocket-Extensions头确认对端是否回以permessage-deflate;若响应头中包含该扩展,则说明压缩已协商成功。运行时 API 的完整方法与事件清单(accept、close、send、addEventListener等)可参考 WebSocket 运行时 API。兼容性日期到达前的存量 Worker:只要
compatibility_date早于 2023-08-15 且未显式添加标志,历史行为(剥离/忽略Sec-WebSocket-Extensions)保持不变,因此该改动对存量服务无破坏性。代理场景需关注关闭行为:如果 Worker 使用
fetch()方式在客户端与后端之间代理 WebSocket 并启用了压缩,请一并关注web_socket_auto_reply_to_close标志对关闭流程的影响——半开行为需要通过accept({ allowHalfOpen: true })显式恢复。浏览器客户端自动协商:浏览器端的
new WebSocket(url)会自动发送permessage-deflate,因此启用标志后,浏览器客户端与 Worker 之间的消息将自动获得压缩传输,开发者无需修改客户端代码。
总结
web_socket_compression是 Workers 兼容性体系的一个典型代表:它用"默认保持旧行为、显式或随日期切换新行为"的方式,将运行时从"忽略Sec-WebSocket-Extensions"平滑演进到"完整遵循 WebSocket 压缩 RFC"。启用该标志后,无论通过new WebSocket(url)自动协商还是fetch()手动携带permessage-deflate头,运行时都会在入站与出站连接上应用压缩;配合no_web_socket_compression回退、RFC 7692 压缩参数以及同族的其它 WebSocket 标志,开发者可以在不破坏存量行为的前提下,为实时通信链路引入更高效的传输编码。
【免费下载链接】cloudflare-docsCloudflare’s documentation项目地址: https://gitcode.com/GitHub_Trending/cl/cloudflare-docs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考