• 如何使用 JavaScript 检测用户是否启用三方 Cookie ?
  • 发布于 2个月前
  • 113 热度
    0 评论
今天来聊一聊  Cookie ,Chrome 已经在 1.4 号开启了三方 Cookie 的 1% 禁用灰度:Chrome 三方 Cookie 禁用已正式开始!

不少小伙伴反馈已经命中了这个灰度,因为时间比较急,很多网站来不及改造,很多网站的正常功能在这个灰度策略下受到了影响。对于一些还没来得及改造完的网站,Chrome 提供了一种便捷的方式来让命中灰度的用户手动关闭这个策略:

这个开关点击后可以允许指定域名继续使用三方 Cookie ,但是这个期限只有 90 天。

所以,如果大家的网站最近没有时间进行这些改造,大家可以在运行时来提示用户手动关闭三方 Cookie 的禁用策略。那么问题来了,并不是所有用户都命中了这个策略,当前只有 1% ,我们可能给所有的用户都添加这个提示,所以我们如何在运行时检测用户是否命中了三方 Cookie 的灰度策略呢?
function checkCookie(){
    var cookieEnabled = navigator.cookieEnabled;
    if (!cookieEnabled){ 
        document.cookie = "testcookie"; 
        cookieEnabled = document.cookie.indexOf("testcookie")!=-1;
    }
    return cookieEnabled || showCookieFail();
}

function showCookieFail(){
  // do something here
}

checkCookie();
上面的代码片段可用于检查 Cookie 是否启用,但是对三方 Cookie 的检查就无能为力了,三方 Cookie 禁用的情况下还是会返回 true。我能想到的并且一直有效的方法就是添加一个外部(三方)的 iFrame,让它来检测 iFrame 内部是否可以访问到 Cookie,并且会将 Cookie 的可用状态通知给父应用。

虽然这听起来挺奇怪的,我们好像无法直接通过 iFrame 调用父页面的功能。但是我们可以使用 Message Event 来进行父子应用之间的通信,通过这个我们可以基于 URL 向其他浏览器发送消息,在我们现在这种情况下,我们可以从 iFrame 向可能在不同域上的父应用发送消息。

首先,我们在 iFrame 内添加一个立即执行函数。在这个函数中,我们添加一个消息事件监听器,这个监听器会在从父级应用程序调用时触发。当被调用时,它首先会验证请求,然后调用 checkCookiesEnable 函数来检查 Cookie 的状态并返回结果。然后,我们通过 parent.postMessage() 方法向父应用发送一条消息;在 iFrame 中,parent 是一个隐含的对象。
<!doctype html>
<html>
<head>
<title>堆代码 duidaima.com </title>
</head>
<body>
    <script>
        const checkCookiesEnable = () => {
            let isCookieEnabled = (window.navigator.cookieEnabled) ? true : false;
            if (typeof window.navigator.cookieEnabled == "undefined" && !isCookieEnabled) {
                // 尝试设置一个测试cookie
                document.cookie = "testcookie";
                // 检查cookie是否已设置
                isCookieEnabled = (document.cookie.indexOf("testcookie") != -1) ? true : false;
            }

            return isCookieEnabled;
        }

        // 监听消息事件,响应从父窗口传来的消息
        (function () {
            window.addEventListener('message', event => {
                try {
                    let data = JSON.parse(event.data)
                    if (data['test'] !== 'cookie')
                        return
                    let result = checkCookiesEnable();
                    // 将结果通过消息事件发送到父窗口
                    parent.postMessage(JSON.stringify({
                        'result': result
                    }), event.origin);
                }
                catch (e) {
                    console.error(e)
                }
            });
        })();
    </script>
</body>
</html>
在这里,我们将添加一个消息事件处理程序,然后在插入任何第三方脚本之前插入我们的 iFrame。一旦 iFrame 加载完毕,我们将通过 frame.contentWindow 对象向我们的 iFrame 发送 postMessage,使用 "*" 允许 postMessage 任何来源(不同的域)。

然后,iFrame 内部的函数检查iFrame 的 Cookie 状态并发送一个消息,该消息被我们的 messagehandler 拦截。检查消息是否由 iFrame 发送,事件现在将保存来自 iFrame 内的 checkCookieEnable 函数结果的响应。

下面是一个示例函数,它接受iframeUri和一个回调函数,在收到结果后将被调用。
const cookieTest = (iFrameUri, callBack) => {
    let messageHandler = (event) => {
        // 在这里检查受信任的来源
        const data = JSON.parse(event.data);
        callBack(data['result']);
        window.removeEventListener('message', messageHandler);
        document.body.removeChild(frame);
    };

    // 监听消息事件,响应从 iframe 窗口传来的消息
    window.addEventListener('message', messageHandler);

    // 创建并添加一个隐藏的 iframe 元素
    const frame = document.createElement('iframe');
    frame.src = iFrameUri;
    frame.sandbox = "allow-scripts allow-same-origin";
    frame.style = `display:none`;
    frame.onload = (e) => {
        // 向 iframe 发送一个消息,请求检查 cookie 的情况
        frame.contentWindow.postMessage(JSON.stringify({ 'test': 'cookie' }), '*');
    };

    document.body.appendChild(frame);
};

export default cookieTest;
你可以直接把上面的代码片段放入你的网站中,并提供一个回调函数来为用户呈现适当的消息。

现在,我们可以成功地在运行时检测到用户的第三方 Cookie 是否已启用了!
用户评论