getHTML() – 替代 innerHTML 的最佳方法

随着所有主流浏览器现已支持 getHTML() 方法,前端开发者有了一个强大的新工具来操作DOM。本文主要探讨 getHTML()的独特优势,特别是在处理Shadow DOM时的卓越表现。

getHTML()innerHTML 的 getter 在基本功能上相似,都返回元素内部DOM树的HTML表示。但getHTML()的真正优势在于它能够包含Shadow DOM的HTML,而innerHTML则完全忽略Shadow DOM。

getHTML()接受一个可选的options对象参数,通过适当的选项可以获取完整的HTML,包括Shadow DOM:

这段代码会返回包含声明式Shadow Root的完整HTML:

如果在浏览器中将返回的 上面的 HTML 作为新页面打开,则会再现原始 DOM 树:

通常,shadow trees和slots是在自定义元素的构造函数中创建的,但为了保持上面和下面示例页面中的代码简单,这里没有创建任何自定义元素。相反,使用了两个辅助函数:

div(n)创建一个新的div元素,里面包含数字n,例如<div>123</div>,而attach(host)将HTML为<p>Paragraph <slot>default</slot></p>的shadow树附加到host元素上。为了用常见情况挑战getHTML(),div中的数字123被分配到shadow DOM的slot中。

在上面的页面中,getHTML()被调用时使用了所有两个可能的选项:

options对象可以有两个属性:serializableShadowRoots和shadowRoots。当getHTML()在没有options的情况下被调用时,Shadow DOM会被忽略,就像在innerHTML中一样。

如果serializableShadowRoots为true,HTML将包括具有serializable属性设置为true的shadow roots。这样的roots通常不应该存在,因为serializable是与getHTML()一起引入的,默认情况下它是false。

要获取shadow roots的HTML,需要在shadowRoots属性中提供要序列化的shadow roots。当shadow roots是open的时候,可以很容易地递归检索网页中的所有shadow roots。在网页上下文中无法检索closed shadow roots,但可以在浏览器扩展注入的内容脚本中检索。

提供的shadow roots不一定会被序列化。在下一个示例页面中,创建了两个shadow trees。第二个shadow DOM嵌套在第一个中:

如果第一个shadow DOM不包含在options中,getHTML()不会返回第二个shadow DOM的HTML:要被序列化,shadow roots需要直接连接到要被序列化的DOM。如果省略了父shadow root,嵌套的shadow root也不会被序列化。

  1. 缺少outerHTML等价物:目前还没有获取包含元素自身在内的HTML的方法。
  2. 单根元素限制:getHTML()返回的HTML如果没有单一根元素,浏览器可能无法正确解析为声明式Shadow DOM。
  3. 封闭的Shadow DOM:在网页上下文中无法获取封闭的Shadow DOM,但可以通过浏览器扩展的内容脚本来实现。

getHTML()为开发者提供了一种强大的方法来处理包含Shadow DOM的复杂DOM结构。虽然它有一些限制,但在处理现代Web组件和复杂UI时,getHTML()的优势是显而易见的。随着Web组件的普及,掌握getHTML()将成为前端开发者的重要技能。

在实际开发中,getHTML()可以用于创建更精确的DOM快照、调试复杂的组件结构,以及在需要保留Shadow DOM结构的情况下序列化页面内容。随着Web标准的不断发展,我们可以期待看到更多类似getHTML()这样的强大API,进一步增强前端开发的能力和灵活性。

React 如何避免 XSS 攻击?

Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击!

XSS 指:恶意代码未经处理,与正常代码混淆在一起,浏览器无法辨别哪些脚本是可靠的,导致恶意脚本被执行。由于恶意脚本在客户端执行(实际上就是获取了客户端内的部分控制权),从而可以直接获取用户信息,或者利用这些信息冒充真实用户向服务器发起攻击。

xss

通常注入的手段有如下方式:

1. 用户 UGC 内容,比如在表单内输出一段恶意脚本,服务器未经校验,直接进行存储,当其他客户端请求该资源时,则会在客户端上执行恶意脚本;

2. URL 参数,攻击者诱骗用户点击一个带有恶意代码的按钮 URL, 通过脚本内容在 URL 参数内,用户点击后,可能将该恶意脚本填充到 HTML 内,从而导致恶意脚本被执行;

3. POST 参数,这类难度较大,通过诱导用户填写相应内容来实现;

4. Cookie,可能来自其他子域的注入;

XSS 类型

根据注入手段的不同,通常将 XSS 攻击分为三类:存储型 XSS、反射型 XSS 以及存储型 XSS,这里不再进行赘述,参考相关文章即可。

事实上,大部分的 XSS 都发生在前后不分离的系统设计内,因为其代码和数据不分离的关系,导致存储型和反射型 XSS 都是在服务端取出恶意代码后,插入到 HTML 里的,攻击者刻意编写的“数据”被内嵌到“代码”中,被浏览器所执行。

demo

通过对 XSS 深入了解,我们知道,XSS 攻击过程可以抽象为两步:

1. 攻击者提交恶意脚本;

2. 客户端执行恶意脚本;

通常防御的手段是:

1. 对 UGC 内容进行转义,即服务端不信任任何客户端的数据(这是一个好习惯);

2. 开启白名单,防止恶意跳转;

3. 对 Cookie 设置 HTTP only,将数据放在服务端维护;

但是,React 这了前后分离(数据和代码分离)的架构实际上已经规避了大部分的 XSS 攻击手段。除此之外,React 实现了一套独立于浏览器的浏览器 DOM 系统,它能够防止通过 HTML 注入恶意代码,比如:

react

React 会将插入变量转换为字符串,除非你在代码中通过 dangerouslySetInnerHTML 来插入 HTML 元素。

同时,React 在处理样式时,`style` 接受一个采用小驼峰命名属性的 JavaScript 对象,而不是 CSS 字符串。这与 DOM 中 `style` 的 JavaScript 属性是一致的,同时会更高效的,且能预防跨站脚本(XSS)的安全漏洞!

Solo with code!

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。