更新时间:2024-08-14 19:50:31
HTMLRewriter
类允许开发者在CDNetworks Edge Cloud Apps函数中构建全面且富有表现力的 HTML 解析器。它提供了一个简化的 JavaScript API,用于解析和转换 HTML,使开发者能够直接在函数中构建功能强大的应用程序,体验类似于 jQuery 的操作方式。
要使用 HTMLRewriter
类,请在您的 Worker 脚本中实例化它一次,并使用 on
和 onDocument
函数附加各种处理程序。
new HTMLRewriter().on('*', new ElementHandler()).onDocument(new DocumentHandler());
HTMLRewriter
API 一致地使用以下类型用于各种属性和方法:
Content
插入到输出流中的内容应为字符串。
ContentOptions
{ html: Boolean }
控制 HTMLRewriter
如何处理插入的内容。如果 html
布尔值设置为 true
,则内容将被视为原始 HTML。如果 html
布尔值设置为 false
或未提供,则内容将被视为文本,并将对其应用正确的 HTML 转义。
HTMLRewriter
使用两种类型的处理程序:元素处理程序和文档处理程序。
元素处理程序使用 HTMLRewriter
实例的 .on
函数附加时,会响应传入的元素。元素处理程序应响应 element
、comments
和 text
。以下示例使用 ElementHandler
类处理 div
元素。
class ElementHandler {
element(element) {
// 传入的元素,例如 `div`
console.log(`传入元素: ${element.tagName}`);
}
comments(comment) {
// 传入的注释
}
text(text) {
// 传入的文本片段
}
}
async function handleRequest(req) {
const res = await fetch(req);
return new HTMLRewriter().on('div', new ElementHandler()).transform(res);
}
文档处理程序表示传入的 HTML 文档。可以在文档处理程序上定义许多函数来查询和操作文档的 doctype
、comments
、text
和 end
。与元素处理程序不同,文档处理程序的 doctype
、comments
、text
和 end
函数不受特定选择器的限制。这些函数会针对页面上的所有内容(包括顶级 HTML 标签之外的内容)调用:
class DocumentHandler {
doctype(doctype) {
// 传入的文档类型,例如 <!DOCTYPE html>
}
comments(comment) {
// 传入的注释
}
text(text) {
// 传入的文本片段
}
end(end) {
// 文档的结尾
}
}
在元素和文档处理程序上定义的所有函数都可以返回 void
或 Promise<void>
。将处理程序函数设为 async
允许您访问外部资源,例如通过 fetch
、Workers KV、Durable Objects 或缓存访问 API。
class UserElementHandler {
async element(element) {
let response = await fetch(new Request('/user'));
// 使用响应填充用户信息
}
}
async function handleRequest(req) {
const res = await fetch(req);
// 在 ID 为 `user_info` 的 div 上通过 HTMLRewriter 运行用户元素处理程序
return new HTMLRewriter().on('div#user_info', new UserElementHandler()).transform(res);
}
element
参数仅在元素处理程序中使用,它表示一个 DOM 元素。element
上存在许多方法可以查询和操作它:
tagName
标签的名称,例如 “h1” 或 “div”。可以为该属性分配不同的值,以修改元素的标签。
attributes
(只读)
标签属性的 [name, value]
对。
removed
指示元素是否已被删除或被之前的某个处理程序替换。
namespaceURI
表示元素的命名空间 URI。
getAttribute(name)
:
返回元素上给定属性名称的值,如果未找到,则返回 null
。
hasAttribute(name)
:
返回一个布尔值,指示元素上是否存在属性。
setAttribute(name, value)
:
将属性设置为提供的值,如果属性不存在,则创建该属性。
removeAttribute(name)
:
删除属性。
before(content, contentOptions)
:
在元素之前插入内容。有关 Content
和 ContentOptions
的更多信息,请参阅 全局类型。
after(content, contentOptions)
:
在元素之后插入内容。
prepend(content, contentOptions)
:
在元素的开始标签之后插入内容。
append(content, contentOptions)
:
在元素的结束标签之前插入内容。
replace(content, contentOptions)
:
删除元素并在其位置插入内容。
setInnerContent(content, contentOptions)
:
替换元素的内容。
remove()
:
删除元素及其所有内容。
removeAndKeepContent()
:
删除元素的开始标签和结束标签,但保持其内部内容不变。
onEndTag(handler)
:
注册一个处理程序,当元素的结束标签到达时调用该处理程序。
endTag
参数仅在使用 element.onEndTag
注册的处理程序中使用,它是 DOM 元素的有限表示。
name
标签的名称,例如 “h1” 或 “div”。可以为该属性分配不同的值,以修改元素的标签。
before(content, contentOptions)
:
在结束标签之前插入内容。
after(content, contentOptions)
:
在结束标签之后插入内容。有关 Content
和 ContentOptions
的更多信息,请参阅 全局类型。
remove()
:
删除元素及其所有内容。
由于 CDNetworks 执行零拷贝流式解析,因此文本块与词汇树中的文本节点不同。一个词汇树文本节点可以由多个块表示,因为它们是从源服务器通过网络到达的。
考虑以下标记:<div>Hey. How are you?</div>
。Worker 脚本可能不会立即从源服务器接收整个文本节点。相反,文本元素处理程序将为接收到的文本节点的每个部分调用。例如,处理程序可能会使用“Hey. How ”调用,然后使用“are you?”调用。当最后一个块到达时,文本的 lastInTextNode
属性将设置为 true
。开发者应确保将这些块连接在一起。
removed
指示元素是否已被删除或被之前的某个处理程序替换。
text
(只读)
块的文本内容。如果块是文本节点的最后一个块,则可能为空。
lastInTextNode
(只读)
指定块是否是文本节点的最后一个块。
before(content, contentOptions)
:
在元素之前插入内容。有关 Content
和 ContentOptions
的更多信息,请参阅 全局类型。
after(content, contentOptions)
:
在元素之后插入内容。
replace(content, contentOptions)
:
删除元素并在其位置插入内容。
remove()
:
删除元素及其所有内容。
元素处理程序上的 comments
函数允许开发者查询和操作 HTML 注释标签。
class ElementHandler {
comments(comment) {
// 传入的注释元素,例如 <!-- 我的注释 -->
}
}
comment.removed
指示元素是否已被删除或被之前的某个处理程序替换。
comment.text
注释的文本。可以为该属性分配不同的值,以修改注释的文本。
before(content, contentOptions)
:
在元素之前插入内容。有关 Content
和 ContentOptions
的更多信息,请参阅 全局类型。
after(content, contentOptions)
:
在元素之后插入内容。
replace(content, contentOptions)
:
删除元素并在其位置插入内容。
remove()
:
删除元素及其所有内容。
文档处理程序上的 doctype
函数允许开发者查询文档的文档类型。
class DocumentHandler {
doctype(doctype) {
// 传入的文档类型元素,例如
// <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
}
}
doctype.name
(只读)
文档类型名称。
doctype.publicId
(只读)
PUBLIC
原子之后文档类型中的带引号的字符串。
doctype.systemId
(只读)
SYSTEM
原子之后或紧跟 publicId
之后文档类型中的带引号的字符串。
文档处理程序上的 end
函数允许开发者将内容附加到文档的末尾。
class DocumentHandler {
end(end) {
// 文档的结尾
}
}
append(content, contentOptions)
:
在文档末尾之后插入内容。有关 Content
和 ContentOptions
的更多信息,请参阅 全局类型。
选择器是用于选择 HTML 文档中特定元素的模式。HTMLRewriter
支持各种 CSS 选择器。以下是一些示例:
Selector | Description |
---|---|
* |
Any element. |
E |
Any element of type E . |
E:nth-child(n) |
An E element, the nth child of its parent. |
E:first-child |
An E element, the first child of its parent. |
E:nth-of-type(n) |
An E element, the nth sibling of its type. |
E:first-of-type |
An E element, the first sibling of its type. |
E:not(s) |
An E element that does not match the selector s . |
E.warning |
An E element belonging to the class warning . |
E#myid |
An E element with ID equal to myid . |
E[foo] |
An E element with a foo attribute. |
E[foo="bar"] |
An E element whose foo attribute value is exactly equal to “bar”. |
E[foo~="bar"] |
An E element whose foo attribute value is a list of whitespace-separated values, one of which is exactly equal to “bar”. |
E[foo^="bar"] |
An E element whose foo attribute value begins exactly with the string “bar”. |
E[foo$="bar"] |
An E element whose foo attribute value ends exactly with the string “bar”. |
E[foo*="bar"] |
An E element whose foo attribute value contains the substring “bar”. |
E F |
An F element descendant of an E element. |
E > F |
An F element child of an E element. |
如果处理程序抛出异常,解析将立即停止,转换后的响应体将因抛出的异常而出错,未转换的响应体将被取消(关闭)。如果转换后的响应体已经部分流式传输回客户端,则客户端将看到一个截断的响应。
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);
// 此时,像 `await newResponse.text()` 这样的表达式
// 将抛出 `new Error("A really bad error.")`。
// 此后,任何使用 `newResponse.body` 的操作都将抛出相同的错误,
// `oldResponse.body` 将被关闭。
// 或者,这将向客户端产生一个截断的响应:
return newResponse;
}