iframe中新开窗口不会携带sessionStorage跟localStorage

你是否遇到了localStorage不共享的情况?sessionStorage不在原来页面的clone基础上?

场景

主项目在域名main.cn中用iframe的方式嵌入其他系统,比如A系统a.domain.cn以及B系统b.domain.cn等。A,B系统通过监听postmessage方式获取主项目的用户信息存储在sessionStorage中,来让A,B系统的鉴权。但是A,B系统中通过window.open 打开的页面(同源)都因为获取不到sessionStorage而鉴权不成功,而导致不可以正常加载页面

方案汇总

一、给window.open的页面发送postMessage通信

  1. 修改window.open方法,给window.open的页面发送postMessage通信
typescript 复制代码
export const windowOpen = (url: string, windowName = '') => {
    const target = window.open(
      url,
      windowName,
      'toolbar=no'
    );
    if(target){
      // 不要直接postMessage,不然target接收不到,因为那个时候页面还没有加载
      target.addEventListener('DOMContentLoaded',()=>{
        target.postMessage({
          token: '鉴权信息'
        },location.origin)
      }) 
    }
  };
  1. 监听message事件
javascript 复制代码
  window.addEventListener('message', (e) => {
    console.log('postmessage收取到信息', e.data)
    sessionStorage.setItem('token', e.data.token)
    if(e.origin == location.origin){
      // 重新加载页面
      window.location.reload()
    }
  });
  1. 优化下,window.open是先进入login页面再跳转到目标页面,直接空白而不是进入login页面。这跟JS的event loop有关,event loop是在脚本执行后才开始轮询
javascript 复制代码
  const RequireAuth = ({ children }: { children: JSX.Element }) => {
  
    const token = sessionStorage.getItem('token');
    const location = useLocation();

    if (!token && window.opener) {
      // 解决浏览器版本升级后,iframe嵌入的形式中window.open不会携带原本的sessionStorage信息导致跳转到login页面 优化为空白页面
      return ""
     }
    
    if (!token) {
      return <Navigate to="login" state={{ from: location }} replace />;
    }
    return children;
  };
  export default RequireAuth;

二、改为localStorage的存储

心想sessionStorage不共享,localStorage总共享吧

修改后发现window.open的页面还是没办法正常加载,localStorage原来也不共享 了。我在思索这里面的原因是主项目跟iframe内嵌页面是跨域的。window.open打开的页面是否跨域不取决于内嵌页面,而在于主项目,所以有跨域了

最后才发现可以直接window.opener.localStorage.getItem(key)去获取iframe内嵌页面的localStorage

javascript 复制代码
 if(window.opener){
    return window.opener.localStorage.getItem('token');
  }

PS:

localhost的访问形式。localStorage是共享的,sessionStorage是会在原来的基础上

非localhost的域名,localStorage是互不影响的,sessionStorage不复制

PS: 盲猜???浏览器对localhost的形式跨域限制比较宽容??

三、最终解决 直接获取window.opener.sessionStorage

kotlin 复制代码
export const getSessionStorageValue = function (key: string) {
  const val = sessionStorage.getItem(key)
  if(val){
    return val;
  }
  if(window.opener){
    // fix: iframe下window.open不会携带window.opener的sessionStorage信息
    return window.opener.sessionStorage.getItem(key);
  }
  return ""
};

总结

  • sessionStorage跟localStorage都遵从同源策略
  • main.cn系统中以iframe的形式嵌入B系统(b.domain.cn),在iframe中打开B系统的页面a.html,window.open('/a')会被浏览器认为不同源,从而导致sessionStorage没有从iframe克隆过来,localStorage不共享
  • window.open打开的如果是同源页面,会返回一个WindowProxy对象,可以访问原本的window的信息,可以获取localStorage,sessionStorage
  • 通过window.opener可以获取到原本窗口的引用。window.opena标签且rel="noopener"的页面
  • localhost模式开发跟直接a.domain.cn的开发模式,浏览器对sessionStorage跟localStorage的处理有差异性
相关推荐
WeiXiao_Hyy9 分钟前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡26 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone32 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09011 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king1 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳2 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_3 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js