data: URL Worker 八年都能直接读 localStorage,Chrome 157 用 opaque origin 把它锁死了

写过 Web Worker 的人,大概都知道 Worker 里拿不到 localStorage。但 Chrome 149 开始,这个「拿不到」变成了字面意思——Worker 不再和主页面共享同一个 origin,而是被分配了一个独立的 opaque origin,连 localStorage、cookies、IndexedDB 都读不到了。更关键的是:企业 IT 用来临时维持旧行为的那扇后门(DataUrlInWebWorkerOpaqueOriginEnabled 策略),将在 Chrome 157 彻底移除,届时所有依赖旧行为的内部应用将被迫迁移。


发生了什么:旧行为 vs 新行为

Chrome 149 之前(旧行为):

// index.html(同源页面)
localStorage.setItem('token', 'abc123');
const worker = new Worker('data:text/javascript,postMessage(localStorage.getItem("token"))');
// Worker 继承了主页面的 origin → 可以访问 localStorage

Chrome 149~156(过渡期):默认行为变为 opaque origin,但企业可配 DataUrlInWebWorkerOpaqueOriginEnabled=0 策略回退。

Chrome 157 之后(新行为):

// 主页面的 localStorage token='abc123'
const worker = new Worker('data:text/javascript,postMessage(localStorage.getItem("token"))');
// Worker 有独立 opaque origin → localStorage.getItem("token") 返回 null
// IndexedDB/cookies 同样访问不到

这不只是 Chrome 自己的决定——它是 WHATWG HTML 规范 的要求。Firefox 和 Safari 早已如此,Chrome 是在补全合规性。


为什么有 8 个月的过渡窗口

这次变更有破坏性。Chrome 团队很清楚:许多内部企业应用用 data: URL 方式嵌入 Worker 脚本,目的是想在 Worker 里直接读主页面存的认证 token、用户偏好等数据。直接切断会直接 break 一批业务。

所以 Chrome 149 引入了临时策略 DataUrlInWebWorkerOpaqueOriginEnabled:

  • Enabled(默认):新安全行为,Worker 独立 opaque origin
  • Disabled:回退到旧行为,Worker 继承创建页面的 origin

企业 IT 有 8 个月时间(149→157)逐步迁移代码,而不是被迫在某个版本升级后立即崩溃。

但这扇后门只在 149~156 期间有效。Chrome 157 将移除该策略,届时无论是否配置,Worker 都强制 opaque origin,不再有任何回退手段。


怎么判断你的代码是否受影响

如果你的代码符合以下任一模式,就需要注意:

// 场景1:data: URL Worker 直接读 localStorage
const worker = new Worker(
  'data:text/javascript,self.onmessage=()=>postMessage(localStorage.getItem("user"))'
);

// 场景2:SharedWorker 用 data: URL 跨标签共享状态
const shared = new SharedWorker(
  'data:text/javascript,self.onconnect=function(e){...}'
);

// 场景3:Worker 内部写 IndexedDB
const worker = new Worker(
  'data:text/javascript,onmessage=e=>{ let db=indexedDB.open("app"); }'
);

检查方法:在 Chrome 149+ 环境打开 DevTools,在 Worker 里跑一行 console.log(localStorage.length),如果返回 0 就说明已经受影响。


迁移方案

方案一:通过 postMessage 主动传参(推荐)

不再让 Worker 自己去读,而是主页面主动把需要的数据通过 postMessage 传进去:

// 主页面
const token = localStorage.getItem('token');
const worker = new Worker('/worker.js');
worker.postMessage({ token }); // 主动传,不依赖 Worker 自己读

// worker.js
self.onmessage = (e) => {
  const { token } = e.data;
  // 用 token 做事
};

方案二:用 importScripts 替代 data: URL

如果 Worker 逻辑复杂,用独立 JS 文件 + importScripts 替代 data: URL,可以更干净地控制脚本来源和缓存。

方案三:MessageChannel 做双向通信桥

如果 Worker 和主页面需要双向状态同步,用 MessageChannel 建立专用通道:

const channel = new MessageChannel();
// 主页面端
parentPort.postMessage({ type: 'get-token' });
// 主页面的 message handler 根据请求类型读取 localStorage 再发回去

降级策略:检测 + 优雅提示

Chrome 157 之后策略移除,无法再回退。但可以在代码里做 Feature Detection:

if (typeof Worker !== 'undefined') {
  const testWorker = new Worker('data:text/javascript,void 0');
  let canAccessStorage = false;
  testWorker.onmessage = () => { canAccessStorage = true; };
  testWorker.postMessage('test');
  setTimeout(() => {
    if (!canAccessStorage) {
      console.warn('当前环境 data: URL Worker 无法访问 localStorage,请使用 postMessage 传参');
    }
  }, 100);
}

时间节点速记

版本 行为
Chrome 148 及之前 Worker 继承创建页面 origin(可访问 localStorage)
Chrome 149 默认 opaque origin;DataUrlInWebWorkerOpaqueOriginEnabled 策略可临时回退
Chrome 157 策略移除,强制 opaque origin,无回退

如果你是企业 IT 管理员:Chrome 157 预计在 2026 年第四季度 稳定版发布,迁移窗口只剩几个月。

如果你是前端开发者:现在就去搜一下项目里有没有 new Worker('data: 这类写法,有的话尽快改成 postMessage 主动传参,别等政策窗口关闭后被动 hotfix。

评论区

0 条评论

登录后可评论。