如何检测页面是否允许访问Cookie

如何检测页面是否允许访问Cookie

1. 检测API

书接上文,如果浏览器设置了禁止访问cookies,将导致如 无法访问localStorage 等异常报错。这类错误是由用户的浏览器设置导致的,如果开发者没有拿到出问题的现场及相关日志,是比较难排查的。那么有没有方法可以在代码里检查页面是否允许访问cookies呢?

答案肯定是有的,浏览器为我们开发者提供了一个贴心的api:Navigator.cookieEnabled。这是一个只读属性,返回一个布尔值,来表示当前页面是否启用了 cookie。这个属性已经被主流浏览器实现了(除了IE这个奇葩,不过现在微软也放弃他了),所以可以放心大胆地用。

2. 如何检测

cookie可以分为两大类,一个是本地cookie,一个是第三方cookie。下面将分别介绍他们的检测方案:

2.1 本地cookie

本地cookie最简单,navigator里面存储的就是当前页面的状态和标识,所以直接读取即可。

if (!navigator.cookieEnabled) {
  // 浏览器不支持 cookie,或者用户禁用了 cookie。
}

2.2 第三方cookie

第三方cookie的一般形式是通过iframe加载第三方网站的时候,iframe内部的cookie即为第三方cookie。第三方网站的内容一般是跨域的,无法访问到其内容,也无法进行修改,因而无法直接使用上面的方法读取其内部的cookie访问状态。

我们换个思路,其实不一定需要主页面“主动”获取第三方网站的cookie访问状态,也可以由第三方网站自行检测cookie访问状态后“通知”父页面。而且对于浏览器来说,只要是非同源的网站,都是可以认为是第三方的。那我们可以自行构建一个能够自行检测cookie状态的第三方网站,然后将cookie访问状态通过postMessage回传给父页面就可以了。

自建第三方网站
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    window.onload = () => {
      window.parent.postMessage(JSON.stringify({ cookieEnabled: navigator.cookieEnabled }), '*');
    }
  </script>
</body>
</html>
主页面
export const CookieDetector = (callback: (data: any) => void) => {
  let ifrm: any = document.createElement('iframe');
  const timeout = setTimeout(() => {
    window.removeEventListener('message', test);
    ifrm.remove();
    ifrm = null;
    callback(true);
  }, 1000);
  const test = (data: any) => {
    clearTimeout(timeout);
    try {
      const jsonData = JSON.parse(data);
      window.removeEventListener('message', test);
      ifrm.remove();
      ifrm = null;
      callback(jsonData.cookieEnabled);
    } catch (e) {
      // do nothing
    }
  };
  window.addEventListener('message', (event: any) => test(event.data));
  document.body.appendChild(ifrm);
  ifrm.onload = () => {
    clearTimeout(timeout);
  };
  ifrm.src = ''; // 自建第三方网站地址
};