本地存储
本地存储
cookie
如何工作
网页发HTTP请求时,浏览器会先检查是否有相应的cookie
,有则自动添加在request header
中的cookie
字段中。
问题
存储在cookie
中的数据,每次都被浏览器自动放在HTTP请求中,若这些数据并不是每个请求都需要发给服务器的数据,浏览器设置自动处理便增加了网络开销;若这些数据是每个请求都需要携带的数据,浏览器设置自动处理就免去了重复添加操作。
因此,在cookie
中,最适合存放每次请求都要携带的数据(典型的就是身份认证信息)
cookie标准限制
每个域名下cookie大小最大为4 KB,每个域名下的cookie数量最多为20个
属性
expires|max-age
设置cookie什么时间内有效
- expires
expires=w,D M Y h:m:s GMT
表示cookie将在Y年M月D日h时m分s秒星期w之后失效,失效的cookie浏览器会清空- 未设置expires,默认有效期为session,即会话cookie,浏览器关闭后消失
- http1.0协议中的选项
- max-age
max-age=正数
cookie有效期为创建时刻+max-age
max-age=0
删除cookiemax-age=负数
cookie有效期为session
- http1.1协议中的选项,替代了expires
domain&path
domain是域名,path是路径,二者共同构成url,一起限制cookie能被哪些url访问
domain = 'd.com'; path='/p'
对于域名是d.com
或其子域为xxx.d.com/xxx.xxx.d.com
,且路径是/p
或子路径/p/xxx
,浏览器会将此cookie添加到该请求的cookie头部中- 未设置,domain默认值为该cookie的网页所在的域名;path默认值为设置该cookie的网页所在的目录
发送跨域请求时,即使url的域名和路径都满足cookie的domain和path,默认情况下cookie也不会自动添加到请求头部中
secure
设置cookie只在确保安全的请求中才会发送,当请求是HTTPS或其他安全协议时,包含secure选项的cookie才能被发送至服务器
document.cookie='key=value; secure'
当请求是安全协议的情况下,才会发送给服务器,在控制台还是可以看到该cookie的- 未设置,默认情况下cookie不会带secure选项。因此,默认情况下,不管是否为安全协议的请求,cookie都会被发送到服务器。
- 若在网页中通过js设置secure类型的cookie,必须保证网页是HTTPS协议的
HttpOnly
设置cookie是否能通过js访问,默认情况下,cookie不会带httpOnly选项,客户端可以通过js代码访问(读取、修改、删除等)该cookie
- HttpOnly只能通过服务端设置
- 限制客户端访问cookie,是为了保障安全。例如:某页面遭受XSS攻击时,有一段恶意脚本插到了网页中,该脚本通过
document.cookie
读取用户身份验证相关的cookie,并将这些cookie发送到攻击者的服务器,攻击者轻而易举地拿到用户验证信息
设置cookie
服务端设置
Set-Cookie=Path=/;Expires=Thu,01-Jan-1970 00:00:00 GMT;...
- 一个
set-cookie
只能设置一个cookie,设置多个cookie,需要添加多个set-cookie
字段 - 服务端可以设置cookie的所有选项:expires|domain|path|secure|HttpOnly
客户端设置
document.cookie='name=value;expire=...;secure'
- 一个
document.cookie
只能设置一个cookie,设置多个cookie,需要添加多个document.cookie
字段 - 客户端可以设置cookie的选项:expires|domain|path|secure(只能在HTTPS协议中设置成功)
修改删除cookie
修改cookie
path|domain选项保持一致,其他选项重新赋值,便能修改该cookie
删除cookie
path|domain选项保持一致,expires选项设置为一个过去的时间,或者max-age设置为负数,便能删除该cookie
跨域请求中的cookie
cookie作为一种credential信息(还有HTTP authentication schemes
),发生跨域时,默认情况下不会被传送给服务器。除非客户端手动设置xhr.withCredentials=true
,服务端必须允许request能携带认证信息,即在response header
中包含Access-Control-Allow-Credentials:true
,这样浏览器才会自动将cookie加在request header
中。并且,服务端不能将Access-Control-Allow-Origin
设置为*,而必须设置为请求页面的域名。
WebStorage
localStorage
特点
- 生命周期:持久化的本地存储,除非主动删除,否则数据永不过期
- 存储的信息在同一域中是共享的
- 大小:5M
使用
- 设置:
localStorage.setItem('key','value')
- 获取:
- 获取value
localStorage.getItem('key')
- 获取第n+1个key
localStorage.key(n)
- 获取value
- 删除:
localStorage.removeItem('key')
- 清除:
localStorage.clear()
sessionStorage
特点
- 生命周期:会话级别的存储。存储一个会话的数据,在同一个会话中的页面的数据才能被访问,当会话结束后数据也随之销毁。
使用
- 设置:
sessionStorage.setItem('key','value')
- 获取:
- 获取value
sessionStorage.getItem('key')
- 获取第n+1个key
sessionStorage.key(n)
- 获取value
- 删除:
sessionStorage.removeItem('key')
- 清除:
sessionStorage.clear()
cookie|WebStorage的区别
cookie | localStorage | sessionStorage | |
---|---|---|---|
大小 | 4 KB | 5 MB | 5 MB |
生命周期 | expires|max-age,过期时间前均有效 | 持久化存储,除非手动删除 | 会话结束后消失 |
数据存储 | 数据在每一次HTTP请求时,会携带给服务器 | 只在本地存储 | 只在本地存储 |
作用域 | 域名&路径一致,共享cookie | 协议&主机名&端口一致,共享一份localStorage数据 | 协议&主机名&端口&同一窗口(浏览器的标签页)一致,共享一份sessionStorage数据 |
indexedDB
WebStorage适用于存储少量数据。indexedDB适用于存储大量的结构化数据,是基于JavaScript的面向对象的数据库,允许存储和检索用键索引的对象
使用模式
-
打开数据库并开始一个事务
var db; var request = window.indexedDB.open(dbName, version); request.onsuccess = function(event){ db = request.result; } request.onerror = function(evetn){ alert('error'); }
-
创建一个object store
//在onupgradeneeded事件内操作 request.onupgradeneeded = function(event){ db = event.target.result; var objectStore = db.createObjectStore('item',{keyPath:'id',autoIncrement:true}); //创建索引通过id搜索 /** objectStore.createIndex(indexName,keyPath,objectParameters); indexName:创建的索引名,可为空 keyPath:索引使用的关键路径,可为空,或是keyPath objectParameters:可选参数。unique标识该字段是否唯一,不能重复 */ objectStore.createIndex('id','id',{unique:true}); //添加信息到数据库 objectStore.add(name:'nnn',age:'aa'); } //在onupgradeneeded事件外操作 //新建事务 var transaction = db.transaction(['item'],'readwrite'); //创建存储对象 var objectStore = transaction.objectStore('item'); //添加数据 objectStore.add({name:'nnn',age:'aa'});
-
构建一个请求来执行一些数据库操作(新增或提取数据)
//获取数据 var getRequest = objectStore.get(1); //修改数据 var updateRequest = objectStore.put({name:'aaa',age:'gg',id:1}); //删除数据 var deleteRequest = objectStore.delete(1);