Safari Private 模式下 localStorage 的问题
现如今好多浏览器都有「隐身模式」,Safari 管这叫「Private Browing」,国内各种牌子的套壳浏览器叫「无痕浏览」。私以为从命名上来说,倒是国内更中文一些。
这种模式下浏览网页踏雪无痕,雁过不留声。具体来说,与正常模式的区别是浏览器不会保存历史记录,没有页面缓存,所有本地数据也都是临时的,页面关闭后无法还原。譬如本文下面要讲到的 localStorage
。
--------- LOG --------- 00:01:00 - 一位不具名用户在零点零一分进行了访问 00:02:00 - 一位不愿透露姓名的用户在零点零二分打开了你丢弃在服务器 `社会科学/东方艺术鉴赏/东瀛国浮世绘` 中的资源 `ae2bx86.jpg`
从功能上来说,普通用户大概鲜有人知道这一功能(产品情怀就这样被用户无视,PM 们默默泪目),而开发者则利用其干净的特点来开发调试,排除程序之外的因素导致 bug 的可能。
因为所有本地数据都是临时的,那么问题来了,如果网页代码中还使用了诸如 localStorage
的本地存储,还能生效吗?
答案是肯定的,但只针对本次访问。这个肯定只限于桌面浏览器。 而手机端则不然。
iOS 上 Safari private 模式下浏览器假装支持 localStorage
,并在全局 window
上暴露了该方法。但是当你在调用 localStorage.setItem
进行保存的时候就会报 QUOTA_EXCEEDED_ERR
错。
QUOTA_EXCEEDED_ERR:DOM Exception 22:An attempt was made to add something to storage...
考察下面的测试代码:
<button class="setValue">SET</button> <hr> <button class="getValue">GET</button> <script> var q = document.querySelector; document.querySelector('.setValue').onclick = function () { try { var time = new Date().getTime(); localStorage.setItem('time', time); alert('set '+time); } catch (error) { alert(JSON.stringify(error)); } } document.querySelector('.getValue').onclick = function () { var content = localStorage.getItem('time', new Date().getTime()); alert('got '+content); } </script>
我在页面放了两个按钮,一个用于向浏览器保存值,一个用于获取。
下面是测试结果:
iOS Safari 隐私模式设置值
iOS Safari 隐私模式获取值
iOS Chrome 隐私模式设置值
iOS Chrome 隐私模式获取值
这表明在 iOS 上,不仅是 Safari 在隐私模式中不能使用 localStorage
, Chrome 也不行也不行。这不禁让人怀疑跟系统平台的策略有关。
博主是谷粉,很早就入手了 Nexus。本着严谨的做事态度,那肯定也得拿来测试一下丫。而安卓机上的测试则让人无法接受。
安卓 Chrome 隐私模式下设置值
安卓 Chrome 隐私模式下获取值
是的,安卓上面并没有表现出假装支持 localStorage
,而是真正的支持,能存能取,能取能用!再次证实了上面的怀疑,这种假装的支持应该是 iOS 的设计哲学。
回过头来想,隐私模式主要的功能不就是让用户的数据不被追踪吗,如果能够存取数据的话,反而没那么隐私了。从这点来说,localStorage
设置不成功倒也考量了些许人文情怀在里面。
问题想当于回到了开发者手中,我们在开发过程中使用 loaclStorage
就需要对这种情况进行兼容,以避免 js 报错后影响整个页面的功能。
下面是兼容代码示例:
function isLocalStorageSupport(){ try { var isSupport = 'localStorage' in window && window['localStorage'] !== null; if (isSupport) { localStorage.setItem('__test', '1'); localStorage.removeItem('__test'); } return isSupport; } catch (e) { return false; } }
为此,我们可以考虑提取一个辅助类来封装 localStorage
,这样就可以随时随地放心使用。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
实现Android主流网络框架封装,可无缝侵入切换框架
一、什么是“有多种可替代解决方案的业务逻辑”? 举几个例子说明: 客户端的http请求操作,可以实现的方案有Retrofix、OkHttp、Volley等; 客户端的数据库存储方案可以为Realm、greenDao、OrmLite等; 图片加载的方案可以是Fresco、Glide、Picasso、UIL等。 二、如何快速替换? 先来描述一下需求,比如说,目前正在用的http请求是Volley,现在发现使用OkHttp来封装一套会更好。又比方说,目前正在用的数据存储方案是OrmLite,现在使用greenDao或者Realm会更好,在类似这些情况下,如何做到不修改Activity/Fragment/Presenter代码的情况下,把Volley的http请求实现更换成Okhttp的实现,把OrmLite更换成greenDao或者Realm? 解决问题的关键词:设计模式中的——工厂方法模式。 本质:利用接口进行解耦。 说到这里,可能很多有经验的朋友已经会心一笑,是的,老实说这篇文章可能对老司机没有太大的意义,但是如果看到这里还是心存疑问,或者你不知道什么是工厂方法模式,也不知道如何使用接...
- 下一篇
Android -- 面试 -- 数据库升级策略
升级:重写onUpgrade方法 确定 相邻版本 的差别,从版本1开始依次迭代更新,先执行v1到v2,再v2到v3…… 为 每个版本 确定与现在数据库的差别,为每个case撰写专门的升级代码。 降级 onDowngrade()数据库降级:比如从数据库4降级到数据库3必须重写该方法。 @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { super.onDowngrade(db, oldVersion, newVersion); } 迁移数据: 将现有表重命名为临时表; 创建新表; 将临时表的数据导入新表(注意处理修改的列); 删除临时表。 protected void upgradeTables(SQLiteDatabase db, String tableName, String columns) { try { db.beginTransaction(); // 1, 将现有表重命名为临时表 String tempTableName = tableName + ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装Docker,最新的服务器搭配容器使用
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7安装Docker,走上虚拟化容器引擎之路