开发H5 webapp时经常需要使用本地存储,与最多能存4k的cookie相比,localStorage和sessionStorage的优势明显。因此在公司的一个项目中我是用了localStorage来替代cookie。但是却不知道缺隐藏着一些未知因素。事情是这样的,客服说有一个用户怎么都登录不了,明明用户名密码是正确的,但就是登录不了,很是奇怪。经过一番的折腾才明白,原来用户使用的Safari的无痕模式浏览,localStorage对象仍然存在,但是localStorage的setItem对象会报出异常QuotaExceededError,getItem和removeItem则直接忽略(undefined)。这相当于你有一台手机但是却打不了电话…

解决

知道了原因以后就好解决了,当时的思路是两个:

  • 每当遇到存储操作时判断是否是无痕模式,是无痕模式就使用cookie,不是就使用sessionStorage
  • 整套换掉使用cookie

个人倾向于第二种的,但是当时大佬说用第一种。那么说干就干,由于我们使用的是zepto.js而且zepto.cookie.js只提供了set的方法,所以还需要自己封装cookie操作。首先我们来看怎么判断是否为无痕模式,使用try/catch就可以判断了,如果报出异常就是无痕模式,使用cookie,反之就使用localStorage。

1
2
3
4
5
6
7
8
9
10
// 判断是否为无痕模式
getType: function(){
try{
localStorage.setItem('test', 'testValue');
localStorage.removeItem('test');
return 'localStorage';
}catch (error){
return 'cookie';
}
},

然后我们定义一个storage对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var storage = {
getType: function(){
try{
localStorage.setItem('test', 'testValue');
localStorage.removeItem('test');
return 'localStorage';
}catch (error){
return 'cookie';
}
},
setItem: function(item, itemValue) {
if(this.getType == 'cookie'){
//使用cookie的setItem
}else{
//使用localStorage的setItem
}
},
getItem: function(item) {
if(this.getType == 'cookie'){
//使用cookie的getItem
}else{
//使用localStorage的getItem
}
},
removeItem: function(item) {
if(this.getType == 'cookie'){
//使用cookie的removeItem
}else{
//使用localStorage的removeItem
}
},
clear: function() {
if(this.getType == 'cookie'){
//使用cookie的clear
}else{
//使用localStorage的clear
}
}
}

看来以后在移动端使用localStorage和sessionStorage还是要小心啊,注意Safari这一个坑。