Chrome 控制台偶尔出现:
[Violation] Permissions policy violation: unload is not allowed in this document.
不是代码报错,是一条警告。
原因
Chrome 正在逐步废弃 unload 事件,因为注册了 unload 的页面无法进入 BFCache(Back/Forward Cache),会降低导航性能。某些页面策略或 iframe 设置下,unload 会被直接禁止,此时任何注册 unload 的代码都会打印这条 Violation。
常见触发场景:
- 第三方 SDK(Sentry、埋点、广告脚本)注册了
unload - 旧版 Citrix/Enterprise 插件
- 页面在
<iframe>里,父页面设置了Permissions-Policy: unload=()
是否影响功能
通常不影响。[Violation] 只是警告,页面照常运行,unload 回调不会执行而已。如果你的业务逻辑依赖 unload(如发送离开事件),需要改用 visibilitychange 或 pagehide。
查看当前页面的 Permissions Policy
方法一:Network 响应头
打开 DevTools → Network,刷新页面,点击 HTML 文档请求 → Response Headers,查找:
Permissions-Policy: unload=()
方法二:控制台查询
// 查看 unload 是否被策略禁止
document.permissionsPolicy?.allowsFeature("unload")
// 查看所有允许的特性
document.permissionsPolicy.allowedFeatures()
// 抓取当前页面响应头
fetch(location.href)
.then(r => console.log(r.headers.get("Permissions-Policy")))
定位是谁注册了 unload
// 查看 window 上注册了哪些 unload 监听器
getEventListeners(window).unload
// 查看 beforeunload
getEventListeners(window).beforeunload
如果有结果,点击 listener 里的函数名可以跳转到 Sources 对应代码。
也可以在 Sources 全局搜索:
addEventListener("unload"
window.onunload
beforeunload
推荐替代方案
// 替代 unload:页面对用户不可见时触发
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
// 发送最后的数据
navigator.sendBeacon("/api/leave", payload);
}
});
// 替代 beforeunload(不阻塞 BFCache)
window.addEventListener("pagehide", (e) => {
if (e.persisted) {
// 页面进入 BFCache,不是真正关闭
}
});
navigator.sendBeacon 在页面隐藏时异步发送请求,不阻塞页面关闭,是发送离开事件的首选方案。
Chrome Extension 的本地存储
Chrome 扩展用 chrome.storage.local 存储的数据保存在:
Windows: %LOCALAPPDATA%\Google\Chrome\User Data\Default\Local Extension Settings\<扩展ID>
macOS: ~/Library/Application Support/Google/Chrome/Default/Local Extension Settings/<扩展ID>
目录内容是 LevelDB 格式(.log、.ldb 文件),不是纯文本。查看方法:
# 在扩展页面控制台读取(需要 Inspect views 权限)
chrome.storage.local.get(null, console.log)
或用 Python plyvel 解析:
import plyvel
db = plyvel.DB("/path/to/extension/storage", create_if_missing=False)
for k, v in db:
print(k.decode(errors="replace"))
print(v.decode(errors="replace"))
db.close()
注意:读取时浏览器需要关闭,否则 LevelDB 文件被锁。
