HTMLRewriter

更新时间:2024-08-14 19:50:31

HTMLRewriter 类允许开发者在CDNetworks Edge Cloud Apps函数中构建全面且富有表现力的 HTML 解析器。它提供了一个简化的 JavaScript API,用于解析和转换 HTML,使开发者能够直接在函数中构建功能强大的应用程序,体验类似于 jQuery 的操作方式。

要使用 HTMLRewriter 类,请在您的 Worker 脚本中实例化它一次,并使用 ononDocument 函数附加各种处理程序。

构造函数

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

全局类型

HTMLRewriter API 一致地使用以下类型用于各种属性和方法:

  • Content

    插入到输出流中的内容应为字符串。

  • ContentOptions

    { html: Boolean } 控制 HTMLRewriter 如何处理插入的内容。如果 html 布尔值设置为 true,则内容将被视为原始 HTML。如果 html 布尔值设置为 false 或未提供,则内容将被视为文本,并将对其应用正确的 HTML 转义。

处理程序

HTMLRewriter 使用两种类型的处理程序:元素处理程序和文档处理程序。

元素处理程序

元素处理程序使用 HTMLRewriter 实例的 .on 函数附加时,会响应传入的元素。元素处理程序应响应 elementcommentstext。以下示例使用 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 文档。可以在文档处理程序上定义许多函数来查询和操作文档的 doctypecommentstextend。与元素处理程序不同,文档处理程序的 doctypecommentstextend 函数不受特定选择器的限制。这些函数会针对页面上的所有内容(包括顶级 HTML 标签之外的内容)调用:

class DocumentHandler {
  doctype(doctype) {
    // 传入的文档类型,例如 <!DOCTYPE html>
  }

  comments(comment) {
    // 传入的注释
  }

  text(text) {
    // 传入的文本片段
  }

  end(end) {
    // 文档的结尾
  }
}

异步处理程序

在元素和文档处理程序上定义的所有函数都可以返回 voidPromise<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

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):

    在元素之前插入内容。有关 ContentContentOptions 的更多信息,请参阅 全局类型

  • after(content, contentOptions):

    在元素之后插入内容。

  • prepend(content, contentOptions):

    在元素的开始标签之后插入内容。

  • append(content, contentOptions):

    在元素的结束标签之前插入内容。

  • replace(content, contentOptions):

    删除元素并在其位置插入内容。

  • setInnerContent(content, contentOptions):

    替换元素的内容。

  • remove():

    删除元素及其所有内容。

  • removeAndKeepContent():

    删除元素的开始标签和结束标签,但保持其内部内容不变。

  • onEndTag(handler):

    注册一个处理程序,当元素的结束标签到达时调用该处理程序。

EndTag

endTag 参数仅在使用 element.onEndTag 注册的处理程序中使用,它是 DOM 元素的有限表示。

属性

  • name

    标签的名称,例如 “h1” 或 “div”。可以为该属性分配不同的值,以修改元素的标签。

方法

  • before(content, contentOptions):

    在结束标签之前插入内容。

  • after(content, contentOptions):

    在结束标签之后插入内容。有关 ContentContentOptions 的更多信息,请参阅 全局类型

  • remove():

    删除元素及其所有内容。

文本块

由于 CDNetworks 执行零拷贝流式解析,因此文本块与词汇树中的文本节点不同。一个词汇树文本节点可以由多个块表示,因为它们是从源服务器通过网络到达的。

考虑以下标记:<div>Hey. How are you?</div>。Worker 脚本可能不会立即从源服务器接收整个文本节点。相反,文本元素处理程序将为接收到的文本节点的每个部分调用。例如,处理程序可能会使用“Hey. How ”调用,然后使用“are you?”调用。当最后一个块到达时,文本的 lastInTextNode 属性将设置为 true。开发者应确保将这些块连接在一起。

属性

  • removed

    指示元素是否已被删除或被之前的某个处理程序替换。

  • text (只读)

    块的文本内容。如果块是文本节点的最后一个块,则可能为空。

  • lastInTextNode (只读)

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

方法

  • before(content, contentOptions):

    在元素之前插入内容。有关 ContentContentOptions 的更多信息,请参阅 全局类型

  • after(content, contentOptions):

    在元素之后插入内容。

  • replace(content, contentOptions):

    删除元素并在其位置插入内容。

  • remove():

    删除元素及其所有内容。

注释

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

class ElementHandler {
  comments(comment) {
    // 传入的注释元素,例如 <!-- 我的注释 -->
  }
}

属性

  • comment.removed

    指示元素是否已被删除或被之前的某个处理程序替换。

  • comment.text

    注释的文本。可以为该属性分配不同的值,以修改注释的文本。

方法

  • before(content, contentOptions):

    在元素之前插入内容。有关 ContentContentOptions 的更多信息,请参阅 全局类型

  • after(content, contentOptions):

    在元素之后插入内容。

  • replace(content, contentOptions):

    删除元素并在其位置插入内容。

  • remove():

    删除元素及其所有内容。

Doctype

文档处理程序上的 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

文档处理程序上的 end 函数允许开发者将内容附加到文档的末尾。

class DocumentHandler {
  end(end) {
    // 文档的结尾
  }
}

方法

  • append(content, contentOptions):

    在文档末尾之后插入内容。有关 ContentContentOptions 的更多信息,请参阅 全局类型

选择器

选择器是用于选择 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;
}
本篇文档内容对您是否有帮助?
有帮助
我要反馈
提交成功!非常感谢您的反馈,我们会继续努力做到更好!