【问题标题】:When do items in HTML5 local storage expire?HTML5 本地存储中的项目何时过期?
【发布时间】:2023-03-20 12:20:02
【问题描述】:

存储在localStorage(作为 HTML5 中的 DOM 存储的一部分)中的数据可用多长时间?我可以为放入本地存储的数据设置过期时间吗?

【问题讨论】:

  • 尽可能不要使用 localStorage,因为它永远不会自动过期,你可以使用 sessionStorage 更可取

标签: javascript html local-storage


【解决方案1】:

我建议将时间戳存储在 object 你存储在 localStorage 中

var object = {value: "value", timestamp: new Date().getTime()}
localStorage.setItem("key", JSON.stringify(object));

您可以解析对象,获取时间戳并与当前日期进行比较,如果需要,更新对象的值。

var object = JSON.parse(localStorage.getItem("key")),
    dateString = object.timestamp,
    now = new Date().getTime().toString();

compareTime(dateString, now); //to implement

或者,您可以使用像 localstorage-slim.js 这样的轻量级包装器来为您处理这个问题。

【讨论】:

  • 好吧,即使客户端时间不一致,您仍然可以找到使用服务器时间的方法。就像将时间戳回显到 div 中一样。
  • 你会解析和比较一个时间间隔内的时间戳(例如settimout 每 5 秒)还是客户端发送到服务器的每个请求?
  • 更好的方法是比较每个用户请求的日期
  • 我建议使用Date.now() 而不是new Date().getTime()
【解决方案2】:

无法指定过期时间。这完全取决于用户。

https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage

当然,您的应用程序存储在客户端上的某些内容可能稍后会不存在。用户可以明确地摆脱本地存储,或者浏览器可能会遇到空间问题。进行防御性编程是件好事。然而,一般来说,根据该词的一些实际定义,事物仍然是“永远”的。

edit — 显然,如果您自己的应用程序认为它太旧,它可以主动删除它。也就是说,您可以在已保存的内容中显式包含某种时间戳,然后稍后使用它来决定是否应刷新信息。

【讨论】:

  • 那么用户可以指望一年后可用的数据吗?除非用户明确删除数据,否则开发人员能否指望数据可用?
  • @AndresRiofrio 我找不到来自 Mozilla 或 Microsoft 或 W3C 的任何规定任何强制到期的文档。因此我认为答案是肯定的,用户代理应该永远保留存储的东西,或者直到用户明确要求删除它(或者我猜直到你自己的应用程序删除它自己的东西)。
  • 这也意味着您的浏览器不断增长。您使用一个应用程序一次,它会将它的内容存储在您的浏览器中,并且它会永远保留在那里......
  • 每个网站可以存储的 localStorage 数据量约为 10mb,但一般网站不会存储超过几个字符串,所以我不介意存储空间
  • Firefox 有一个记录在案的eviction policy here
【解决方案3】:

您可以使用lscache。它会自动为您处理此问题,包括存储大小超过限制的实例。如果发生这种情况,它会开始修剪最接近指定到期时间的项目。

来自readme

lscache.set

Stores the value in localStorage. Expires after specified number of minutes.

Arguments
key (string)
value (Object|string)
time (number: optional)

这是常规存储方法之间唯一真正的区别。获取,删除等工作相同。

如果您不需要那么多功能,您可以简单地存储带有值的时间戳(通过 JSON)并检查它是否过期。

值得注意的是,将本地存储留给用户是有充分理由的。但是,当您需要存储非常临时的数据时,像 lscache 这样的东西确实会派上用场。

【讨论】:

  • 谢谢!这对我的需要来说太棒了——数据只需要在那里,以防用户在保存工作之前发出嘘声或浏览器关闭,但是 cookie 的数据太多。我将它与pieroxy.net/blog/pages/lz-string/index.html结合使用。
【解决方案4】:

Brynner Ferreira 提出了一个很好的观点:在到期信息所在的位置存储同级密钥。这样,如果您有大量的键,或者如果您的值是大型 Json 对象,则无需解析它们即可访问时间戳。

下面是一个改进的版本:

 /*  removeStorage: removes a key from localStorage and its sibling expiracy key
    params:
        key <string>     : localStorage key to remove
    returns:
        <boolean> : telling if operation succeeded
 */
 function removeStorage(name) {
    try {
        localStorage.removeItem(name);
        localStorage.removeItem(name + '_expiresIn');
    } catch(e) {
        console.log('removeStorage: Error removing key ['+ key + '] from localStorage: ' + JSON.stringify(e) );
        return false;
    }
    return true;
}
/*  getStorage: retrieves a key from localStorage previously set with setStorage().
    params:
        key <string> : localStorage key
    returns:
        <string> : value of localStorage key
        null : in case of expired key or failure
 */
function getStorage(key) {

    var now = Date.now();  //epoch time, lets deal only with integer
    // set expiration for storage
    var expiresIn = localStorage.getItem(key+'_expiresIn');
    if (expiresIn===undefined || expiresIn===null) { expiresIn = 0; }

    if (expiresIn < now) {// Expired
        removeStorage(key);
        return null;
    } else {
        try {
            var value = localStorage.getItem(key);
            return value;
        } catch(e) {
            console.log('getStorage: Error reading key ['+ key + '] from localStorage: ' + JSON.stringify(e) );
            return null;
        }
    }
}
/*  setStorage: writes a key into localStorage setting a expire time
    params:
        key <string>     : localStorage key
        value <string>   : localStorage value
        expires <number> : number of seconds from now to expire the key
    returns:
        <boolean> : telling if operation succeeded
 */
function setStorage(key, value, expires) {

    if (expires===undefined || expires===null) {
        expires = (24*60*60);  // default: seconds for 1 day
    } else {
        expires = Math.abs(expires); //make sure it's positive
    }

    var now = Date.now();  //millisecs since epoch time, lets deal only with integer
    var schedule = now + expires*1000; 
    try {
        localStorage.setItem(key, value);
        localStorage.setItem(key + '_expiresIn', schedule);
    } catch(e) {
        console.log('setStorage: Error setting key ['+ key + '] in localStorage: ' + JSON.stringify(e) );
        return false;
    }
    return true;
}

【讨论】:

  • 在 setStorage() 中,else 行不应该是 expires = Math.abs(1000*expires); //make sure it's positive 吗?
  • 只需拨打getStorage 电话。如果您尝试直接访问密钥的_expiresIn 版本,则该密钥将变为..._expiresIn_expiresIn,这当然不存在因此它会删除原始..._expiresIn 密钥,那么下次您访问原始密钥时, ..._expiresIn 不存在,它会删除原始密钥。当我在我的一个项目中遇到这个问题时,我会建议对此进行捕捉。 if(key.indexOf('_expiresIn') &gt; -1) { return localStorage.getItem(key); }
【解决方案5】:

这里强烈推荐使用sessionStorage

  • localStorage 相同,但在会话销毁/浏览器关闭时销毁
  • localStorage 也可以在标签之间共享,而 sessionStorage 只能在当前标签中使用,但刷新页面或更改页面时值不会改变
  • sessionStorage 还有助于减少针对 cookie 的网络流量

设定值使用

sessionStorage.setItem("key","my value");

用于获取价值

var value = sessionStorage.getItem("key");

click here for view api

所有的设置方式都是

  sessionStorage.key = "my val";
  sessionStorage["key"] = "my val";
  sessionStorage.setItem("key","my value");

所有获取方式都是

  var value = sessionStorage.key;
  var value = sessionStorage["key"];
  var value = sessionStorage.getItem("key");

【讨论】:

  • 请注意sessionStorage 不能在标签之间共享数据
【解决方案6】:

虽然本地存储不提供过期机制,但 cookie 可以。只需将本地存储密钥与 cookie 配对,即可轻松确保本地存储可以使用与 cookie 相同的过期参数进行更新。

jQuery 中的示例:

if (!$.cookie('your_key') || !localStorage.getItem('your_key')) {
    //get your_data from server, then...
    localStorage.setItem('your_key', 'your_data' );
    $.cookie('your_key', 1);
} else {
    var your_data = localStorage.getItem('your_key');
}
// do stuff with your_data

本示例使用默认参数设置 cookie 在浏览器关闭时过期。因此,当浏览器关闭并重新打开时,your_data 的本地数据存储会被服务器端调用刷新。

请注意,这与删除本地数据存储并不完全相同,而是在 cookie 过期时更新本地数据存储。但是,如果您的主要目标是能够存储超过 4K 的客户端(cookie 大小的限制),那么 cookie 和本地存储的这种配对将帮助您使用与 cookie 相同的过期参数来实现更大的存储大小.

【讨论】:

  • Cookie 可以被清除,更糟糕的是,可以完全关闭。
  • 我最喜欢这个解决方案,因为它可以让浏览器处理我们存储解决方案的过期问题,而无需使用其他库或手动管理本地存储日期。
  • 请记住,每个请求都会发送 Cookie。
【解决方案7】:

生命周期由应用程序/用户控制。

来自standard

用户代理应该仅出于安全原因或在用户请求时使本地存储区域中的数据过期。用户代理应始终避免在可以访问数据的脚本运行时删除数据。

【讨论】:

    【解决方案8】:

    来自 W3C 草案:

    用户代理应该仅出于安全原因或在用户请求时使本地存储区域中的数据过期。用户代理应始终避免在可以访问数据的脚本运行时删除数据。

    您需要使用 setItem(key, value); 更新您的日程安排;这将使用新数据添加或更新给定键。

    【讨论】:

    • 嗯...也许将日期列为数据的一部分是个好主意?或者每次数据更改时使用不同的密钥。
    【解决方案9】:
    // Functions
    function removeHtmlStorage(name) {
        localStorage.removeItem(name);
        localStorage.removeItem(name+'_time');
    }
    
    function setHtmlStorage(name, value, expires) {
    
        if (expires==undefined || expires=='null') { var expires = 3600; } // default: 1h
    
        var date = new Date();
        var schedule = Math.round((date.setSeconds(date.getSeconds()+expires))/1000);
    
        localStorage.setItem(name, value);
        localStorage.setItem(name+'_time', schedule);
    }
    
    function statusHtmlStorage(name) {
    
        var date = new Date();
        var current = Math.round(+date/1000);
    
        // Get Schedule
        var stored_time = localStorage.getItem(name+'_time');
        if (stored_time==undefined || stored_time=='null') { var stored_time = 0; }
    
        // Expired
        if (stored_time < current) {
    
            // Remove
            removeHtmlStorage(name);
    
            return 0;
    
        } else {
    
            return 1;
        }
    }
    
    // Status
    var cache_status = statusHtmlStorage('cache_name');
    
    // Has Data
    if (cache_status == 1) {
    
        // Get Cache
        var data = localStorage.getItem('cache_name');
        alert(data);
    
    // Expired or Empty Cache
    } else {
    
        // Get Data
        var data = 'Pay in cash :)';
        alert(data);
    
        // Set Cache (30 seconds)
        if (cache) { setHtmlStorage('cache_name', data, 30); }
    
    }
    

    【讨论】:

    • 我喜欢这种方法,因为它不需要先解析数据。
    • 谢谢,我也采用了这种方法来解决我的问题。此外,每次状态检查通过时我都会更新stored_time,这样我就不会在用户过去一个小时一直在积极使用GUI时意外注销用户。只有当页面未使用一个小时时,我才希望它自动注销。
    【解决方案10】:

    如果您熟悉浏览器 locaStorage object,您就会知道没有提供到期时间的规定。但是,我们可以使用 Javascript 添加一个 TTL(生存时间)来使 locaStorage 中的项目在经过一定时间后失效。

    function setLocalStorageItem(key, value, ttl) {
        // `item` is an object which contains the original value
        // as well as the time when it's supposed to expire
        let item = {
            value: value,
            expiry: ttl ? Date.now() + ttl : null
        };
    
        localStorage.setItem(key, JSON.stringify(item));
    }
    
    function getLocalStorageItem(key) {
        let item = localStorage.getItem(key);
        
        // if the item doesn't exist, return null
        if (!item) return null;
    
        item = JSON.parse(item);
        // compare the expiry time of the item with the current time
        if (item.expiry && Date.now() > item.expiry) {
            // If the item is expired, delete the item from storage and return null
            localStorage.removeItem(key);
    
            return null;
        }
        
        return item.value;
    }
    

    【讨论】:

      【解决方案11】:

      如果有人仍在寻找快速解决方案并且不想要 jquery 等依赖项,我编写了一个迷你库,为本地/会话/自定义存储添加过期,您可以在此处找到它的源代码:

      https://github.com/RonenNess/ExpiredStorage

      【讨论】:

        【解决方案12】:

        你可以试试这个。

        var hours = 24; // Reset when storage is more than 24hours
        var now = Date.now();
        var setupTime = localStorage.getItem('setupTime');
        if (setupTime == null) {
             localStorage.setItem('setupTime', now)
        } else if (now - setupTime > hours*60*60*1000) {
            localStorage.clear()
            localStorage.setItem('setupTime', now);
        }
        

        【讨论】:

          【解决方案13】:

          如果有人使用 jQuery 的 jStorage 插件,如果 jStorage 插件可以使用 setTTL 函数添加过期时间

          $.jStorage.set('myLocalVar', "some value");
          $.jStorage.setTTL("myLocalVar", 24*60*60*1000); // 24 Hr.
          

          【讨论】:

            【解决方案14】:

            使用 angular 和 localforage 的解决方法:

            angular.module('app').service('cacheService', function() {
            
              return {
                set: function(key, value, expireTimeInSeconds) {
                  return localforage.setItem(key, {
                    data: value,
                    timestamp: new Date().getTime(),
                    expireTimeInMilliseconds: expireTimeInSeconds * 1000
                  })
                },
                get: function(key) {
                  return localforage.getItem(key).then(function(item) {
                    if(!item || new Date().getTime() > (item.timestamp + item.expireTimeInMilliseconds)) {
                      return null
                    } else {
                      return item.data
                    }
                  })
                }
              }
            
            })
            

            【讨论】:

            • 我检查了网站,但在他们的 API 中没有看到任何“expireTimeInMilliseconds”键。它是未记录/不受支持的设置吗?
            • @PhilOlson 这是我使用localforage 使用的自定义实现。 expireTimeInMilliseconds 不是某个 localforage 属性,而是我用来检查存储的数据是否需要过期的变量。在我的示例中检查 get 函数定义。
            • localforage 不是我期待的轻量级小助手类
            【解决方案15】:

            @sebarmeli 的方法在我看来是最好的,但如果您只希望数据在会话的生命周期内持续存在,那么sessionStorage 可能是更好的选择:

            这是一个维护存储区域的全局对象(sessionStorage) 在页面会话期间可用。页面会话 只要浏览器打开并在页面上存活,就会持续 重新加载和恢复。在新选项卡或窗口中打开页面会导致 要启动的新会话。

            MDN: sessionStorage

            【讨论】:

              【解决方案16】:

              为了搜索者的利益:

              像 Fernando 一样,当存储的值很简单时,我不想添加大量 json。我只需要跟踪一些 UI 交互并保持数据的相关性(例如,用户在结帐前如何使用电子商务网站)。

              这不符合每个人的标准,但有望成为某人的快速复制+粘贴启动器,并省去添加另一个库。

              注意:如果您需要单独检索项目,这将不是很好。

              // Addition
              if(window.localStorage){
                  localStorage.setItem('myapp-' + new Date().getTime(), 'my value');
              }
              
              // Removal of all expired items
              if(window.localStorage){
              
                  // two mins - (1000 * 60 * 20) would be 20 mins
                  var expiryTime = new Date().getTime() - (1000 * 60 * 2);
              
                  var deleteRows = [];
                  for(var i=0; i < localStorage.length; i++){
                      var key = localStorage.key(i);
                      var partsArray = key.split('-');
                      // The last value will be a timestamp
                      var lastRow = partsArray[partsArray.length - 1];
              
                      if(lastRow && parseInt(lastRow) < expiryTime){
                          deleteRows.push(key);
                      }
                  }
                  // delete old data
                  for(var j=0; j < deleteRows.length; j++){
                      localStorage.removeItem(deleteRows[j]);
                  }
              }
              

              【讨论】:

                【解决方案17】:

                Javascript localStorage 没有设置过期时间的选项

                然后我使用这些函数来check supportSetGet

                function ls_support(){
                    return "localStorage" in window&&window["localStorage"]!==null;
                }
                
                function lsset(key,val,exp){
                    if(ls_support()){
                        if(!exp) exp=600;// = 10 minutes Default
                        localStorage[key]=
                            JSON.stringify({
                                "val":val,
                                "exp":~~((new Date()).getTime()/1000)+exp
                            });
                    }
                }
                
                function lsget(key){
                    if(ls_support()){
                        str=localStorage[key];
                        if("undefined"!=typeof(str)&&str.length){
                            try{// is json or not
                                json=JSON.parse(str);
                            }catch(e){// if variable not set via lsset func
                                //json.exp=false;// will return null
                                return str;// will return original variable
                            }
                            if(json.exp){// variable setted via lsset func
                                if(~~((new Date()).getTime()/1000)>json.exp){// expired
                                    delete localStorage[key];
                                }else{
                                    return json.val;
                                }
                            }
                        }
                    }
                    return null;
                }
                

                它似乎工作正常:

                【讨论】:

                • 非常好。我用过
                猜你喜欢
                • 1970-01-01
                • 2012-02-27
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-05-07
                相关资源
                最近更新 更多