Angular微前端如何向壳应用设置Cookie与localStorage
核心前提判断
先明确两个部署/加载属性,方案完全由这两个属性决定:
- widget和消费应用是否同域(包括同主域、可通过
document.domain设置共域的场景) - widget是通过脚本直接嵌入运行在消费应用上下文,还是通过iframe独立上下文加载
同域场景方案(无兼容问题,零额外接入成本)
同域场景下不受同源策略限制,只要拿到消费应用的真实窗口对象,就能直接操作存储。
- 脚本嵌入模式(umd/ESM直接引入、运行在消费应用JS上下文)
注意不要使用微前端沙箱(qiankun、wujie、micro-app等)代理的假window对象,直接取顶层真实window调用存储API即可,写入的就是消费应用当前域名下的存储:// 取消费应用真实顶层窗口,自动适配沙箱、单层iframe嵌套场景 const appWindow = window.top || window.parent || window; // 写localStorage appWindow.localStorage.setItem('calendar_widget_last_visit', Date.now().toString()); // 写cookie,path设为/保证全站可访问 appWindow.document.cookie = `calendar_widget_theme=dark;path=/;max-age=31536000;SameSite=Lax`; - iframe加载模式(同域iframe)
和脚本嵌入逻辑完全一致,通过window.parent拿到消费应用的window对象,直接调用上述API即可,没有权限障碍。
跨域场景方案(受同源策略约束,需极低配合成本)
跨域场景下不存在零侵入直接写入的方案:浏览器同源策略是安全基线,禁止跨域上下文直接操作对方窗口的DOM、存储等API,第三方Cookie已被Chrome、Firefox等主流浏览器默认拦截,不要尝试用第三方Cookie实现,兼容性不足10%。
以下两个方案接入成本都极低,不需要改造消费应用现有业务逻辑:
- 方案1:postMessage全局监听(推荐,接入成本10行代码)
作为widget提供方,你不需要提前和消费应用预置通信通道,只需要约定统一的消息格式,widget加载后主动向父窗口发写入请求;消费应用只需要在全局加一次通用监听,即可支持所有组织内共享widget的存储写入需求,一次接入永久复用。
widget端发消息代码:
消费应用全局监听代码(加一次即可):// 向父窗口发存储写入请求,targetOrigin替换为你们组织的域名匹配规则,禁止用* const payload = { source: 'org_internal_widget', action: 'set_storage', storageType: 'localStorage', // 传cookie则写'cookie' key: 'calendar_widget_config', value: JSON.stringify({defaultView: 'month', firstDayOfWeek: 1}), cookieOption: {path: '/', maxAge: 31536000, Secure: true} } window.parent.postMessage(payload, 'https://*.your-internal-org.com');window.addEventListener('message', (e) => { // 校验来源,只接受组织内部域名的请求,防恶意篡改 const allowOriginReg = /^https:\/\/[a-zA-Z0-9-]+\.your-internal-org\.com$/; if (!allowOriginReg.test(e.origin)) return; const data = e.data || {}; if (data.source !== 'org_internal_widget' || data.action !== 'set_storage') return; if (data.storageType === 'localStorage') { window.localStorage.setItem(data.key, data.value); } if (data.storageType === 'cookie') { const opt = data.cookieOption || {}; let cookieSeg = [`${data.key}=${data.value}`, `path=${opt.path || '/'}`]; if (opt.maxAge) cookieSeg.push(`max-age=${opt.maxAge}`); if (opt.Secure) cookieSeg.push('Secure'); if (opt.SameSite) cookieSeg.push(`SameSite=${opt.SameSite}`); document.cookie = cookieSeg.join(';'); } }) - 方案2:同域静态代理页(适合消费应用不想写任何JS代码的场景)
你方提供一个1KB大小的静态代理页widget-storage-proxy.html,消费应用只需要把这个文件放到自己站点的根目录下,不需要写任何JS逻辑。widget运行时动态创建一个隐藏iframe,src指向消费应用域名下的这个代理页,代理页和消费应用同域可直接操作存储,widget和代理页之间通过postMessage通信传递写入指令即可。
代理页核心代码只有几行,消费应用不需要修改,直接托管即可:<!-- widget-storage-proxy.html 消费应用直接放站点根目录 --> <script> window.addEventListener('message', (e) => { const allowOriginReg = /^https:\/\/[a-zA-Z0-9-]+\.your-internal-org\.com$/; if (!allowOriginReg.test(e.origin)) return; const data = e.data || {}; if (data.action === 'set_storage') { // 直接操作当前域(消费应用域)的存储 if (data.storageType === 'localStorage') localStorage.setItem(data.key, data.value); if (data.storageType === 'cookie') { document.cookie = `${data.key}=${data.value};path=/` } // 写完可以给widget回个成功消息 e.source.postMessage({status: 'success'}, e.origin); } }) </script>
避坑提醒
- 所有跨域通信必须做来源校验,禁止将postMessage的targetOrigin设为
*,避免恶意站点嵌套widget后伪造消息篡改消费应用存储。 - 写Cookie时必须加
path=/,否则Cookie默认绑定当前路由路径,消费应用其他页面无法读取。 - 微前端沙箱环境下不要直接用当前上下文的window,必须取
window.top的真实窗口对象,否则写入的存储会落在沙箱的临时内存里,刷新就丢,消费应用主应用也读不到。 - 不要尝试用URL参数、第三方Cookie这类奇技淫巧跨域写存储,要么兼容性差,要么有安全风险。
内容的提问来源于stack exchange,提问作者jslover2020
相关产品推荐
相关产品推荐

