srcdoc是iframe原生属性,用于内联渲染html字符串,不发请求、默认隔离源;它可作轻量沙箱,但必须配sandbox且禁用危险权限。

Srcdoc 是什么,它真能当沙箱用?
srcdoc 是 <iframe></iframe> 的原生属性,允许直接传入 HTML 字符串作为 iframe 内容,绕过跨域限制,且默认继承 sandbox 属性的严格策略(除非显式放开)。它不是“完整沙箱”,但对微模块这类轻量、可控、不需 DOM 通信的场景,足够隔离 JS 执行环境和样式污染——前提是不加 sandbox="allow-scripts allow-same-origin" 这类危险权限。
怎么写一个安全可用的 Srcdoc 微模块?
关键不是“怎么塞内容”,而是“怎么控制执行边界”。以下几点必须做到:
- 所有 HTML 字符串必须经
DOMPurify.sanitize()处理(或至少手动移除<script></script>、onerror、javascript:等),不能直接拼接用户输入或服务端返回的 raw HTML -
<iframe></iframe>必须显式设置sandbox="allow-scripts"(仅需脚本执行)——srcdoc默认禁用脚本,不加这个就啥都跑不了 - 避免使用
document.write或动态document.createElement('script'):它们在srcdociframe 中会被阻断,且无法绕过 - 样式必须内联(
<style></style>块),外部<link>会因sandbox被拦截;CSS 变量、scoped 类名建议加前缀,防父页面样式泄漏
示例:
<iframe srcdoc="<html><body><div class='my-widget'>Hello</div><script>console.log('runs isolated');</script></body></html>" sandbox="allow-scripts" style="width:100%;height:200px;border:none;"></iframe>
为什么不用 iframe src + 后端路由?
对比传统 src="https://widget.example.com/index.html" 方案,srcdoc 的优势很具体:
- 无额外 HTTP 请求:模块代码随主包下发,首屏更快,CDN 缓存更友好
- 天然跨域安全:即使主站是
https://a.com,srcdoc内容也运行在空源("null"),无法读取localStorage或发带 cookie 的请求 - 无服务端依赖:不需要为每个微模块配独立域名或反向代理
- 但代价明确:无法使用
import、无法热更新、无法访问window.parent—— 它就是个单次渲染的封闭盒子
常见报错和兼容性坑
遇到 Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script?这是典型误用:在 srcdoc 里用了异步加载的 script 标签。还有几个硬伤要注意:
-
srcdoc在 IE 完全不支持,Edge 13+ 才可用,移动端 iOS Safari 10.0+、Android Chrome 47+ 支持良好 -
document.domain在srcdociframe 中不可写,也不可读(返回"null"),别试图做跨 iframe 通信 - 如果模块需要调用父应用 API,只能走
window.postMessage,且父应用必须监听message并校验event.source和event.origin - Vue/React 组件直接转
srcdoc字符串会失效——它们依赖挂载点和生命周期,得先用renderToString或hydrateRoot静态输出 HTML 片段
真正难的不是写出来,是守住边界:一旦放开 allow-same-origin 或引入第三方 script 标签,整个隔离就塌了。微模块越轻,越要警惕“顺手加个 analytics”的诱惑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











