跳转到内容
搜索文档

HTMLRewriter

最后更新 查看 MarkdownAgent 设置

背景

HTMLRewriter 类允许开发者在 Cloudflare Workers 应用程序中构建全面且富有表现力的 HTML 解析器。可以将其视为直接在 Workers 应用程序中使用的类似 jQuery 的体验。借助强大的 JavaScript API 来解析和转换 HTML,HTMLRewriter 使开发者能够构建功能丰富的应用程序。

HTMLRewriter 类应在 Workers 脚本中实例化一次,并使用 on 和 onDocument 函数附加多个 handler。


构造函数

new HTMLRewriter()
	.on("*", new ElementHandler())
	.onDocument(new DocumentHandler());

全局类型

在 HTMLRewriter API 中,许多属性和方法使用几种一致的类型:

  • Content string | Response | ReadableStream

  • ContentOptions Object

    • { html: Boolean } 控制 HTMLRewriter 处理插入内容的方式。如果 html 布尔值设为 true,内容将被视为原始 HTML。如果 html 布尔值设为 false 或未提供,内容将被视为文本并应用适当的 HTML 转义。

Handler

HTMLRewriter 可使用两种 handler 类型:元素 handler 和文档 handler。

元素 Handler

元素 handler 响应任何传入元素,通过 HTMLRewriter 实例的 .on 函数附加。元素 handler 应响应 element、comments 和 text。以下示例使用 ElementHandler 类处理 div 元素。

class ElementHandler {
	element(element) {
		// An incoming element, such as `div`
		console.log(`Incoming element: ${element.tagName}`);
	}

	comments(comment) {
		// An incoming comment
	}

	text(text) {
		// An incoming piece of text
	}
}

async function handleRequest(req) {
	const res = await fetch(req);

	return new HTMLRewriter().on("div", new ElementHandler()).transform(res);
}

文档 Handler

文档 handler 表示传入的 HTML 文档。可以在文档 handler 上定义多个函数来查询和操作文档的 doctype、comments、text 和 end。与元素 handler 不同,文档 handler 的 doctype、comments、text 和 end 函数不受特定选择器范围限制。文档 handler 的函数会为页面上的所有内容调用,包括顶层 HTML 标签之外的内容:

class DocumentHandler {
	doctype(doctype) {
		// An incoming doctype, such as <!DOCTYPE html>
	}

	comments(comment) {
		// An incoming comment
	}

	text(text) {
		// An incoming piece of text
	}

	end(end) {
		// The end of the document
	}
}

异步 Handler

元素 handler 和文档 handler 上定义的所有函数都可以返回 void 或 Promise<void>。将 handler 函数设为 async 允许你访问外部资源,例如通过 fetch、Workers KV、Durable Objects 或缓存访问 API。

class UserElementHandler {
	async element(element) {
		let response = await fetch(new Request("/user"));

		// fill in user info using response
	}
}

async function handleRequest(req) {
	const res = await fetch(req);

	// run the user element handler via HTMLRewriter on a div with ID `user_info`
	return new HTMLRewriter()
		.on("div#user_info", new UserElementHandler())
		.transform(res);
}

Element

element 参数仅在元素 handler 中使用,是 DOM 元素的表示。元素上有多个方法可用于查询和操作:

属性

  • tagName string

    • 标签名称,例如 "h1" 或 "div"。此属性可以赋不同值以修改元素的标签。
  • attributes Iterator read-only

    • 标签属性的 [name, value] 对。
  • removed boolean

    • 指示元素是否已被之前的 handler 删除或替换。
  • namespaceURI string

方法

  • getAttribute(name string) : string | null

    • 返回元素上给定属性名称的值,如果未找到则返回 null。
  • hasAttribute(name string) : boolean

    • 返回布尔值,指示元素上是否存在某个属性。
  • setAttribute(name string, value string) : Element

    • 将属性设置为提供的值,如果属性不存在则创建它。
  • removeAttribute(name string) : Element

    • 删除属性。
  • before(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素之前插入内容。
  • after(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素之后立即插入内容。
  • prepend(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素开始标签之后立即插入内容。
  • append(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素结束标签之前立即插入内容。
  • replace(content Content, contentOptions ContentOptionsoptional) : Element

    • 删除元素并在其位置插入内容。
  • setInnerContent(content Content, contentOptions ContentOptionsoptional) : Element

    • 替换元素的内容。
  • remove() : Element

    • 删除元素及其所有内容。
  • removeAndKeepContent() : Element

    • 删除元素的开始标签和结束标签,但保留其内部内容。
  • onEndTag(handler Function<void>) : void

    • 注册在到达元素结束标签时调用的 handler。

EndTag

endTag 参数仅在通过 element.onEndTag 注册的 handler 中使用,是 DOM 元素的有限表示。

属性

  • name string
    • 标签名称,例如 "h1" 或 "div"。此属性可以赋不同值以修改元素的标签。

方法

  • before(content Content, contentOptions ContentOptionsoptional) : EndTag

    • 在结束标签之前插入内容。
  • after(content Content, contentOptions ContentOptionsoptional) : EndTag

    • 在结束标签之后立即插入内容。
  • remove() : EndTag

    • 删除元素及其所有内容。

文本块

由于 Cloudflare 执行零拷贝流式解析,文本块与词法树中的文本节点不是同一概念。词法树文本节点可以由多个块表示,这些块从源站通过网络逐个到达。

考虑以下标记:<div>Hey. How are you?</div>。Workers 脚本可能不会一次性从源站收到整个文本节点;相反,text 元素 handler 会为文本节点的每个接收部分调用。例如,handler 可能先被调用 "Hey. How ",然后是 "are you?"。当最后一个块到达时,text 的 lastInTextNode 属性将设为 true。开发者应确保将这些块连接在一起。

属性

  • removed boolean

    • 指示元素是否已被之前的 handler 删除或替换。
  • text string read-only

    • 块的文本内容。如果块是文本节点的最后一个块,可能为空。
  • lastInTextNode boolean read-only

    • 指定该块是否为文本节点的最后一个块。

方法

  • before(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素之前插入内容。
  • after(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素之后立即插入内容。
  • replace(content Content, contentOptions ContentOptionsoptional) : Element

    • 删除元素并在其位置插入内容。
  • remove() : Element

    • 删除元素及其所有内容。

注释

元素 handler 上的 comments 函数允许开发者查询和操作 HTML 注释标签。

class ElementHandler {
	comments(comment) {
		// An incoming comment element, such as <!-- My comment -->
	}
}

属性

  • comment.removed boolean

    • 指示元素是否已被之前的 handler 删除或替换。
  • comment.text string

    • 注释的文本。此属性可以赋不同值以修改注释文本。

方法

  • before(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素之前插入内容。
  • after(content Content, contentOptions ContentOptionsoptional) : Element

    • 在元素之后立即插入内容。
  • replace(content Content, contentOptions ContentOptionsoptional) : Element

    • 删除元素并在其位置插入内容。
  • remove() : Element

    • 删除元素及其所有内容。

Doctype

文档 handler 上的 doctype 函数允许开发者查询文档的 doctype ↗。

class DocumentHandler {
	doctype(doctype) {
		// An incoming doctype element, such as
		// <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
	}
}

属性

  • doctype.name string | null read-only

    • doctype 名称。
  • doctype.publicId string | null read-only

    • doctype 中 PUBLIC 原子之后的引号字符串。
  • doctype.systemId string | null read-only

    • doctype 中 SYSTEM 原子之后或 publicId 之后立即出现的引号字符串。

End

文档 handler 上的 end 函数允许开发者在文档末尾追加内容。

class DocumentHandler {
	end(end) {
		// The end of the document
	}
}

方法

  • append(content Content, contentOptions ContentOptionsoptional) : DocumentEnd

    • 在文档结束之后插入内容。

选择器

以下是选择器及其用途。

  • *

    • 任何元素。
  • E

    • 任何 E 类型的元素。
  • E:nth-child(n)

    • E 元素,其父元素的第 n 个子元素。
  • E:first-child

    • E 元素,其父元素的第一个子元素。
  • E:nth-of-type(n)

    • E 元素,其同类型兄弟中的第 n 个。
  • E:first-of-type

    • E 元素,其同类型的第一个兄弟。
  • E:not(s)

    • 不匹配任一复合选择器的 E 元素。
  • E.warning

    • 属于 warning 类的 E 元素。
  • E#myid

    • ID 等于 myid 的 E 元素。
  • E[foo]

    • 具有 foo 属性的 E 元素。
  • E[foo="bar"]

    • foo 属性值完全等于 bar 的 E 元素。
  • E[foo="bar" i]

    • foo 属性值完全等于 bar 的任意(ASCII 范围)大小写排列的 E 元素。
  • E[foo="bar" s]

    • foo 属性值完全且大小写敏感地等于 bar 的 E 元素。
  • E[foo~="bar"]

    • foo 属性值为空格分隔的值列表且其中一项完全等于 bar 的 E 元素。
  • E[foo^="bar"]

    • foo 属性值以 bar 字符串开头的 E 元素。
  • E[foo$="bar"]

    • foo 属性值以 bar 字符串结尾的 E 元素。
  • E[foo*="bar"]

    • foo 属性值包含 bar 子字符串的 E 元素。
  • E[foo|="en"]

    • foo 属性值为以 en 开头的连字符分隔值列表的 E 元素。
  • E F

    • E 元素的后代 F 元素。
  • E > F

    • E 元素的子元素 F。

错误

如果 handler 抛出异常,解析会立即停止,转换后的响应 body 会因抛出的异常而报错,未转换的响应 body 会被取消(关闭)。如果转换后的响应 body 已经部分流式传输回客户端,客户端将看到截断的响应。

async function handle(request) {
	let oldResponse = await fetch(request);
	let newResponse = new HTMLRewriter()
		.on("*", {
			element(element) {
				throw new Error("A really bad error.");
			},
		})
		.transform(oldResponse);

	// At this point, an expression like `await newResponse.text()`
	// will throw `new Error("A really bad error.")`.
	// Thereafter, any use of `newResponse.body` will throw the same error,
	// and `oldResponse.body` will be closed.

	// Alternatively, this will produce a truncated response to the client:
	return newResponse;
}

相关资源

这篇文档对您有帮助吗?