William's Blog

如何安全可靠地检测浏览器存储是否可用?

遇到的坑

  最近接触的H5项目需求中需要用到浏览器存储来记录用户足迹,笔者采用判断存储对象是否存在的方法来检验方法来校验浏览器存储是否可用,示例代码如下:

if (window.localStorage) {
    // 这样就认为浏览器存储可用
}

  H5上线后,当其嵌入公司内部app时,页面报错。经过分析和排查,错误的原因在于校验浏览器存储可用性的方法不合理。公司内部app使用的webview版本很老,会禁止浏览器存储的使用,就连访问window对象的localStorage属性也会报错。
  考虑到目前用户手机上存在各种不同特性的浏览器和webview,如何才能安全可靠地检测不同浏览器环境下浏览器存储是否可用?

问题解决方案

  浏览器支持存储功能存储功能可用不是一个概念,比如Safari在隐身模式下会将浏览器localStorage存储容量设置为0,意味着浏览器的存储功能实际不可用,但是Safari是支持浏览器存储功能的。部分浏览器甚至可以让用户设置禁止浏览器存储。因此,笔者在项目中想通过检测window全局对象上是否有localStorage属性来判断当前浏览器localStorage是否可用的方法是非常片面的,只能适用于部分场景。笔者查阅资料后得知,MDN官方文档介绍了一个可以安全可靠地检测浏览器存储可用性的函数,其源码如下:

function storageAvailable(type) {
    try {
        var storage = window[type],
            x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // 当异常是由浏览器存储容量不够造成时,需要排除浏览器存储容量限额为0的特殊情况
            // 非Firefox浏览器存储内容大小超出存储容量时所报出异常的code
            e.code === 22 ||            // Firefox浏览器存储内容大小超出存储容量时所报出异常的code
            e.code === 1014 ||            // 除了检测异常的code属性外,还需要检测异常的name属性,防止部分情况下异常没有code属性
            // 非Firefox浏览器
            e.name === 'QuotaExceededError' ||            // Firefox浏览器
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&            // 排除存储容量不为0的情况
            storage.length !== 0;    }
}

  源码中的高亮部分为不同浏览器环境下判断异常是否是由浏览器存储容量溢出而造成的。需要注意的一点是,存储容量溢出并且存储容量的大小不为0代表浏览器存储是可用的,此时只需要删除部分存储内容即可。
  该可用性检测函数对于localStorage和sessionStorage均适用,在使用浏览器存储前,利用上述函数检测浏览器存储是否可用是安全可靠的。

参考文献

  1. MDN文档:Using the Web Storage API

William

本博客作者 William 现任职于北京贝壳找房,从事web前端开发相关工作。
您可以通过Email与他取得联系