分享一个单页应用cookie互串的解决方案

567 阅读2分钟

现象

客户在浏览器的两个页签里先后使用不同的账号(先 A 后 B)登录了我们的系统,发现账号 B 加完车未结算,切换到账号 A 所在的页签里点击结算,结果账号 B 的钱被扣了。

尴尬了

分析原因

由于我们系统里的 cookie 是种在了同一个域名下,所以后登录的账号 B 会替换掉先登录的账号 A,这样导致用户发送请求时携带的 cookie 都变成了 B。

解决方案

假设大家的项目里已有一个通用的请求方法,这在架构设计初期都会封装好的,通常方法名叫 request,核心代码就是要写在这里面。

以下流程是针对所有账号的,这里以账号 A 为例

  • 首先判断是否有账号 A 的缓存,如果没有就写入,key 为唯一标志(可区分开不同用户,这里以账号为例),值是触发接口时的时间戳(可以是 Date.now())
  • 如果有账号 A 的缓存,就收集 localStorage 里的所有账号(这里是 A 和 B),可以放到一个数组中缓存起来
  • 遍历数组,找到最大时间戳对应的缓存的 key,这里假设是 B
  • 如果这个最大时间戳对应的缓存的 key 和当前账号(假设是 B)匹配,那么就正常操作
  • 如果当前操作的账号(假设是 A)不是最大时间戳对应的 key,就不发送任何接口请求,同时清除掉账号 A 里的所有缓存(这里是 A 和 B)并刷新页面
  • 此时所有页签对应的页面都是账号 B 的了

模拟代码

const request = () => {
    if(!localStorage.getItem('账号 A')) {
	    // 如果缓存不存在,添加缓存
	    localStorage.setItem('账号 A', Date.now())
    } else {
	    // 如果缓存存在,遍历 localStorage,并缓存到一个数组中
	    for(let account in localStorage) {
		    arr.push({
		        [account]: localStorage.getItem(account)
		    });
	    }
	    // 封装一个方法,遍历数组中的每一项,找到最大时间戳对应的账号
	    let max = getMax(arr);  // getMax 方法体省略...

	    if(max === '账号 A') {
	        // 如果最大时间戳对应的账号是当前页签对应的账号,就正常操作,包括更新缓存
	        localStorage.setItem('账号 A', String(Date.now()))
	    } else {
	        // 否则,刷新页面,清空所有账号,并且不发送任何请求
	        location.reload();
	        for(let account in localStorage) {
		        localStorage.removeItem(account)
	        }
	        return;
	    }
    }
}

写在最后

此方案可能不是最佳方案,希望可以抛砖引玉!