Skip to main content
HTMLRewriter 使用 CSS 选择器转换 HTML 文档。它支持 ResponsestringArrayBuffer 输入。Bun 的实现基于 Cloudflare 的 lol-html

用法

一个常见的用例是在 HTML 内容中重写 URL:
重写器会将每张图片替换为 Rick Astley 的缩略图,并将每个 <img> 包裹在链接中,生成如下差异:
现在点击任意图片都会跳转到一段非常著名的视频

输入类型

HTMLRewriter 可以转换多种输入类型的 HTML:
Cloudflare Workers 对 HTMLRewriter 的实现仅支持 Response 对象。

元素处理器

on(selector, handlers) 方法会为匹配 CSS 选择器的 HTML 元素注册处理器。解析过程中,每个匹配的元素都会运行这些处理器:
处理器可以是异步的并返回一个 Promise。转换会在该元素处暂停,直到 Promise 处理完成,因此处理器仍会按照文档顺序逐个运行:
transform(response) 会立即返回;重写会在后台继续进行,你可以从返回的 Response 中读取结果。读取结果会控制重写的速度:流式输入(文件、fetch() 响应、ReadableStream)只会以返回 body 被消费的速度读取,因此缓慢的读取者不会导致整个文档累积在内存中。如果没有读取 body,重写仍会运行每个处理器直到文档末尾,并缓冲输出,直到 body 被读取。由于重写的生命周期会超出 transform(),异步处理器抛出的错误(或其返回的被拒绝的 Promise)会拒绝响应 body,而不会从 transform() 抛出:
stringArrayBuffer 调用 transform() 时,必须同步返回结果,因此无法等待需要事件循环运行的处理器(例如计时器、I/O 或 fetch)。此类处理器会使 transform() 抛出 TypeError,并且重写会失败,不再运行任何后续处理器:
如果处理器的 Promise 在微任务检查点内完成(任何不需要事件循环的操作,包括 process.nextTick 和已经解析的 Promise),则它仍可与 transform(string) 一起使用。如果处理器可能需要等待实际工作,请传入 Response

CSS 选择器支持

on() 方法支持丰富的 CSS 选择器:

元素操作

所有元素修改方法都会返回元素实例,因此可以链式调用:

文本操作

文本块表示文本内容的一部分,并报告其在文本节点中的位置:

注释操作

注释支持与文本节点类似的方法:

文档级处理器

onDocument(handlers) 方法会为文档级别的事件注册处理器,而不是针对特定元素内部的事件:

Response 处理

转换 Response 时:
  • 保留状态码、头部和其他响应属性
  • 转换 body,保持流式能力
  • 自动处理内容编码(如 gzip)
  • 转换后标记原始响应体为已使用
  • 头部被克隆到新响应上。

错误处理

错误通过哪个通道传递,取决于你调用的重载,而不是时机。transform() 本身会针对以下情况抛出错误:
  • on() 方法中的选择器语法无效
  • 输入类型无效(例如传入 Symbol)
  • body 已使用错误,以及输入 body 已经失败或中止
  • stringArrayBuffer 输入,内容处理器引发的任何错误,因为这些输入必须在 transform() 返回前生成结果——包括需要事件循环的处理器(参见元素处理器
对于 Response 输入,transform() 会在重写完成前返回,因此重写过程中发现的所有错误都会通过输出 body 传递:
  • 内容处理器抛出的错误,或其返回的被拒绝的 Promise
  • 格式错误或被截断的输入
  • 读取输入 body 时发生的流错误
  • 内存分配失败
如果处理器创建了 Promise,却既不返回也不等待该 Promise,则该 Promise 的拒绝不会通过上述任何一个通道传递:与任何脱离上下文的拒绝一样,它会进入进程全局的 unhandledRejection 路径。Bun 的早期版本可能会从 transform() 本身暴露该错误。

参考链接

你也可以阅读 Cloudflare 文档,该 API 旨在与之兼容。