我可以通知客户端javascript中的cookie更改

时间:2013-01-15 18:24:39

标签: javascript cookies

我可以在客户端javascript中以某种方式跟踪Cookie(对于我的域)的更改。例如,如果cookie被更改,删除或添加,则会调用一个函数

按优先顺序

  • 标准跨浏览器
  • 跨浏览器
  • 特定于浏览器
  • extension / plugin

为什么呢?因为我在窗口/标签#1中依赖的cookie可以在窗口/标签#2中更改。

我发现chrome允许扩展程序通知Cookie更改。但那是我最不喜欢的选择

6 个答案:

答案 0 :(得分:11)

一种选择是编写一个定期检查cookie以进行更改的函数:

var checkCookie = function() {

    var lastCookie = document.cookie; // 'static' memory between function calls

    return function() {

        var currentCookie = document.cookie;

        if (currentCookie != lastCookie) {

            // something useful like parse cookie, run a callback fn, etc.

            lastCookie = currentCookie; // store latest cookie

        }
    };
}();

window.setInterval(checkCookie, 100); // run every 100 ms
  • 此示例使用闭包来执行持久性内存。外部函数立即执行,返回内部函数,并创建一个私有范围。
  • window.setInterval

答案 1 :(得分:4)

我认为我的方法更好。我写了一个自定义事件来检测何时有机会获得Cookie:

const cookieEvent = new CustomEvent("cookieChanged", {
  bubbles: true,
  detail: {
    cookieValue: document.cookie,
    checkChange: () => {
      if (cookieEvent.detail.cookieValue != document.cookie) {
        cookieEvent.detail.cookieValue = document.cookie;
        return 1;
      } else {
        return 0;
      }
    },
    listenCheckChange: () => {
      setInterval(function () {
        if (cookieEvent.detail.checkChange() == 1) {
          cookieEvent.detail.changed = true;
          //fire the event
          cookieEvent.target.dispatchEvent(cookieEvent);
        } else {
          cookieEvent.detail.changed = false;
        }
      }, 1000);
    },
    changed: false
  }
});

/*FIRE cookieEvent EVENT WHEN THE PAGE IS LOADED TO
 CHECK IF USER CHANGED THE COOKIE VALUE */

document.addEventListener("DOMContentLoaded", function (e) {
  e.target.dispatchEvent(cookieEvent);
});

document.addEventListener("cookieChanged", function (e) {
  e.detail.listenCheckChange();
  if(e.detail.changed === true ){
    /*YOUR CODE HERE FOR DO SOMETHING 
      WHEN USER CHANGED THE COOKIE VALUE */
  }
});

答案 2 :(得分:2)

如果操作Cookie的代码属于您自己,则可以使用localStorage跟踪已更改的事件。例如,您可以在localStorage上存储垃圾以在其他选项卡上触发事件。

例如

var checkCookie = function() {

var lastCookies = document.cookie.split( ';' ).map( function( x ) { return x.trim().split( /(=)/ ); } ).reduce( function( a, b ) { 
        a[ b[ 0 ] ] = a[ b[ 0 ] ] ? a[ b[ 0 ] ] + ', ' + b.slice( 2 ).join( '' ) :  
        b.slice( 2 ).join( '' ); return a; }, {} );


return function() {

    var currentCookies =  document.cookie.split( ';' ).map( function( x ) { return x.trim().split( /(=)/ ); } ).reduce( function( a, b ) { 
        a[ b[ 0 ] ] = a[ b[ 0 ] ] ? a[ b[ 0 ] ] + ', ' + b.slice( 2 ).join( '' ) :  
        b.slice( 2 ).join( '' ); return a; }, {} );


    for(cookie in currentCookies) {
        if  ( currentCookies[cookie] != lastCookies[cookie] ) {
            console.log("--------")
            console.log(cookie+"="+lastCookies[cookie])
            console.log(cookie+"="+currentCookies[cookie])
        }

    }
    lastCookies = currentCookies;

};
}();
 $(window).on("storage",checkCookie); // via jQuery. can be used also with VanillaJS


// on the function changed the cookies

document.cookie = ....
window.localStorage["1"] = new Date().getTime(); // this will trigger the "storage" event in the other tabs.

答案 3 :(得分:2)

方法1:定期轮询

投票document.cookie

function listenCookieChange(callback, interval = 1000) {
  let lastCookie = document.cookie;
  setInterval(()=> {
    let cookie = document.cookie;
    if (cookie !== lastCookie) {
      try {
        callback({oldValue: lastCookie, newValue: cookie});
      } finally {
        lastCookie = cookie;
      }
    }
  }, interval);
}

用法

listenCookieChange(({oldValue, newValue})=> {
  console.log(`Cookie changed from "${oldValue}" to "${newValue}"`);
}, 1000);

document.cookie = 'a=1';

方法2:API拦截

拦截document.cookie

(()=> {
  const channel = new BroadcastChannel('cookie-channel');
  channel.onmessage = (e)=> { // get notification from other same-origin tabs/frames
    document.dispatchEvent(new CustomEvent('cookiechange', {
      detail: e.data
    }));
  };

  let expando = '_cookie';
  let lastCookie = document.cookie;
  let checkCookieChange = ()=> {
    let cookie = document[expando];
    if (cookie !== lastCookie) {
      try {
        let detail = {oldValue: lastCookie, newValue: cookie};
        document.dispatchEvent(new CustomEvent('cookiechange', {
          detail: detail
        }));
        channel.postMessage(detail); // notify other same-origin tabs/frames
      } finally {
        lastCookie = cookie;
      }
    }
  };

  let nativeCookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
  Object.defineProperty(Document.prototype, expando, nativeCookieDesc);
  Object.defineProperty(Document.prototype, 'cookie', { // redefine document.cookie
    enumerable: true,
    configurable: true,
    get() {
      return this[expando];
    },
    set(value) {
      this[expando] = value;
      checkCookieChange();
    }
  });
})();

用法

document.addEventListener('cookiechange', ({detail: {oldValue, newValue}})=> {
  console.log(`Cookie changed from "${oldValue}" to "${newValue}"`);
});

document.cookie = 'a=1';

结论

| Metric \ Method  | Periodic Polling            | API Interception |
| ---------------- | --------------------------- | ---------------- |
| delay            | depends on polling interval | instant          |
| scope            | same-domain                 | same-origin      |

答案 4 :(得分:0)

稍微改进(显示每个更改的cookie的console.log):

var checkCookie = function() {

var lastCookies = document.cookie.split( ';' ).map( function( x ) { return x.trim().split( /(=)/ ); } ).reduce( function( a, b ) { 
        a[ b[ 0 ] ] = a[ b[ 0 ] ] ? a[ b[ 0 ] ] + ', ' + b.slice( 2 ).join( '' ) :  
        b.slice( 2 ).join( '' ); return a; }, {} );


return function() {

    var currentCookies =  document.cookie.split( ';' ).map( function( x ) { return x.trim().split( /(=)/ ); } ).reduce( function( a, b ) { 
        a[ b[ 0 ] ] = a[ b[ 0 ] ] ? a[ b[ 0 ] ] + ', ' + b.slice( 2 ).join( '' ) :  
        b.slice( 2 ).join( '' ); return a; }, {} );


    for(cookie in currentCookies) {
        if  ( currentCookies[cookie] != lastCookies[cookie] ) {
            console.log("--------")
            console.log(cookie+"="+lastCookies[cookie])
            console.log(cookie+"="+currentCookies[cookie])
        }

    }
    lastCookies = currentCookies;

};
}();

window.setInterval(checkCookie, 100);

答案 5 :(得分:0)

我们可以覆盖document.cookie并注意Cookie的更改:

const parseCookies = (cookies = document.cookie) => cookies.split(/; (.*)/).slice(0, -1).map(cookie => {
    const [name, value] = cookie.split("=")
    return [name, decodeURIComponent(value)]
})

const COOKIE = Symbol("Cookie")
let lastCookies = document.cookie
let lastCookiesParsed = new Map(parseCookies(lastCookies))

Object.defineProperty(Document.prototype, COOKIE, Object.getOwnPropertyDescriptor(Document.prototype, "cookie"))

Object.defineProperty(Document.prototype, "cookie", {
    enumerable: true,
    configurable: true,
    get() {
        return this[COOKIE]
    },
    set(value) {
        this[COOKIE] = value

        if (value === lastCookies) {
            return
        }

        for (const [name, cookieValue] of parseCookies(value).filter(([name, cookieValue]) => lastCookiesParsed.get(name) === cookieValue)) {
            document.dispatchEvent(new CustomEvent("cookiechange", {
                detail: {
                    name,
                    value: cookieValue
                }
            }));
        }

        lastCookies = value
        lastCookiesParsed = new Map(parseCookies(lastCookies))
    }
})

用法:

document.addEventListener("cookiechange", ({detail}) => {
    const {name, value} = detail
    console.log(`${name} was set to ${value}`)
})