Translated design docs to English (#19)

* Renamed original documentation files

* Add translated English design docs
This commit is contained in:
Daniël van de Giessen
2026-04-01 12:00:00 +08:00
committed by yz-yu
parent 8b25f74cc5
commit 1a1f6d69a3
10 changed files with 464 additions and 145 deletions

View File

@@ -1,32 +1,27 @@
# 沙盒
# Sandbox
在[序列化设计](./serialization.md)中我们提到了“去脚本化”的处理,即在回放时我们不应该执行被录制页面中的 JavaScript在重建快照的过程中我们将所有 `script` 标签改写为 `noscript` 标签解决了部分问题。但仍有一些脚本化的行为是不包含在 `script` 标签中的,例如 HTML 中的 inline script、表单提交等。
In the [serialization design](./serialization.md) we mentioned the "de-scripting" process, that is, we will not execute any JavaScript in the recorded page during replay, but instead reproduce its effects the snapshots. The `script` tag is rewritten as a `noscript` tag to solve some of the problems. However, there are still some scripted behaviors that are not included in the `script` tag, such as inline scripts in HTML, form submissions, and so on.
脚本化的行为多种多样,如果仅过滤已知场景难免有所疏漏,而一旦有脚本被执行就可能造成不可逆的非预期结果。因此我们通过 HTML 提供的 iframe 沙盒功能进行浏览器层面的限制。
There are many kinds of scripting behaviors. A filtering approach to getting rid of these scripts will never be a complete solution, and once a script slips through and is executed, it may cause irreversible unintended consequences. So we use the iframe sandbox feature provided by HTML for browser-level restrictions.
## iframe sandbox
We reconstruct the recorded DOM in an `iframe` element when we rebuild the snapshot. By setting its `sandbox` attribute, we can disable the following behavior:
我们在重建快照时将被录制的 DOM 重建在一个 `iframe` 元素中,通过设置它的 `sandbox` 属性,我们可以禁止以下行为:
- Form submission
- pop-up window such as `window.open`
- JS script (including inline event handlers and `javascript:` URLs)
- 表单提交
- `window.open` 等弹出窗
- JS 脚本(包含 inline event handler 和 `<URL>`
This is in line with our expectations, especially when dealing with JS scripts is safer and more reliable than implementing this security ourselves.
这与我们的预期是相符的,尤其是对 JS 脚本的处理相比自行实现会更加安全、可靠。
## Avoid link jumps
When you click the a element link, the default event is to jump to the URL corresponding to its href attribute. During replay, we will ensure visually correct replay by rebuilding the page DOM after the jump, and the original jump should be prohibited.
## 避免链接跳转
Usually we will capture all an elements click events through the event handler proxy and disable the default event via `event.preventDefault()`. But when we put the replay page in the sandbox, all the event handlers will not be executed, and we will not be able to implement the event delegation.
当点击 a 元素链接时默认事件为跳转至它的 href 属性对应的 URL。在重放时我们会通过重建跳转后页面 DOM 的方式保证视觉上的正确重放,而原本的跳转则应该被禁止执行。
When replaying interactive events, note that replaying the JS `click` event is not nessecary because click events do not have any impact when JS is disabled. However, in order to optimize the replay effect, we can add special animation effects to visualize elements being clicked with the mouse, to clearly show the viewer that a click has occurred.
通常我们会通过事件代理捕获所有的 a 元素点击事件,再通过 `event.preventDefault()` 禁用默认事件。但当我们将回放页面放在沙盒内时,所有的 event handler 都将不被执行,我们也就无法实现事件代理。
重新查看我们回放交互事件增量快照的实现,我们会发现其实 `click` 事件是可以不被重放的。因为在禁用 JS 的情况下点击行为并不会产生视觉上的影响,也无需被感知。
不过为了优化回放的效果,我们可以在点击时给模拟的鼠标元素添加特殊的动画效果,用来提示观看者此处发生了一次点击。
## iframe 样式设置
由于我们将 DOM 重建在 iframe 中,所以我们无法通过父页面的 CSS 样式表影响 iframe 中的元素。但是在不允许 JS 脚本执行的情况下 `noscript` 标签会被显示,而我们希望将其隐藏,就需要动态的向 iframe 中添加样式,示例代码如下:
## iframe style settings
Since we're rebuilding the DOM in an iframe, we can't affect the elements in the iframe through the CSS stylesheet of the parent page. But if JS scripts are not allowed to execute, the `noscript` tag will be displayed, and we want to hide it. So we need to dynamically add styles to the iframe. The sample code is as follows:
```typescript
const injectStyleRules: string[] = [
@@ -42,4 +37,4 @@ for (let idx = 0; idx < injectStyleRules.length; idx++) {
}
```
需要注意的是这个插入的 style 元素在被录制页面中并不存在,所以我们不能将其序列化,否则 `id -> Node` 的映射将出现错误。
Note that this inserted style element does not exist in the original recorded page, so we can't serialize it, otherwise the `id -> Node` mapping will be wrong.