Web客户端存储是一个现代Web应用必不可少的功能,常见的有Cookie、WebStorage和IndexedDB等,如何选择一个合适的Web存储方案呢?
一. Cookie
1. 为什么要有Cookie?
HTTP协议是无状态的,即一次请求和响应就是一次完整地HTTP通信,多个请求之间是没有会话状态的。但是,现代Web应用一般是有会话状态的。例如:
- 用户身份认证:用户登录后进入下一页面,如何判断当前请求是哪个用户?
- 购物车:用户选中商品后进入下一页面继续购物,如何获取用户之前选中的商品呢?
所以,就有了Cookie,用于解决HTTP协议无状态的问题。
Cookie是服务器返回并保存在浏览器本地的数据,浏览器下次请求时会自动带上Cookie信息。
2. Cookie是怎么实现的?
服务器将Cookie信息存放在 Set-Cookie header,浏览器收到响应后会保存到本地,之后对该服务器的请求都会通过 Cookie header带上Cookie信息。
服务器响应报文:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[页面内容]
浏览器请求报文:
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
常见应用场景:
- 保持会话状态:用户身份认证和购物车功能。
- 跨站追踪:第三方Cookie追踪用户行为,实现广告精准投放。
例如,当用户登录认证后,服务端生成一个Cookie并返回给浏览器,浏览器下次请求时带上Cookie,这样服务端就识别用户身份信息了。PS:一般把真实信息存放在数据库,然后关联一个token存放到Cookie中。
下面是Cookie的相关属性:
a. 有效期
- 会话期 Cookie :仅在会话期内有效,浏览器关闭之后它会被自动删除。
- 持久性 Cookie:在指定有效期Expires或Max-Age后失效。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
b. 作用域
domain/path 定义了Cookie的作用域,即允许 Cookie 被发送给哪些域名。domain默认是origin的域名。
set-cookie: token=123; domain=.bing.com;path=/;
- Cookie可以在子域名之间共享。例如,单点登录,用户在网站boss.com登录后保存Cookie,之后进入子网站a.boss.com时会携带Cookie,服务端就知道是哪个用户了。
- Cookie是禁止跨域的。即domain为www.a.com的Cookie禁止被发送到www.b.com。
c. 安全性
Cookie是存储在浏览器端,并通过HTTP报文在网络上传输,所以需要考虑安全性问题。下面是几种常见的安全问题和Cookie属性。
- Secure
Cookie是通过HTTP报文在浏览器和服务器之间传输,有man-in-the-middle attack的风险。 Secure属性要求Cookie 只能被HTTPS请求携带,从而保证Cookie的安全传输。
但是,能访问到客户端硬盘的人依然能读取到Cookie。所以Cookie不应该携带敏感信息
。
- HttpOnly
HttpOnly表示禁止浏览器端脚本读写Cookie,防范XSS(跨站脚本攻击)。
Cookie本来就是给服务器辨别请求来源的,对浏览器端程序应该无感。通常,服务器完成用户身份认证后,设置Set-Cookie header并指定HttpOnly,而不是由前端脚本拿到数据后再去设置Cookie。
- SameSite
当Cookie的domain属性不是当前网站域名和父级域名时,称为第三方Cookie,存在CSFR风险。
SameSite有以下三个值:
- None:不限制第三方Cookie。
- Strict:禁止第三方Cookie。
- Lax(默认值),与
Strict
类似,但允许导航到目标网站时携带第三方Cookie。
默认使用Lax,限制第三方Cookie,但允许导航到目标网站时携带第三方Cookie,例如<a>、<link>和<form>get请求。但禁止<img>、<iframe>和ajax等请求携带第三方Cookie。
示例:
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly;SameSite=Lax;
第三方Cookie常用来跨站追踪。例如:单点登录和广告精准投放。示例:
- 用户进入购物网站shopping.boss.com后服务端返回Cookie(domain=.boss.com)。
- 之后用户的搜索和点击行为会被记录到数据库。
- 当用户访问了嵌入购物网站广告组件的页面时,会携带Cookie请求广告网站ad.boss.com,广告网站根据Cookie找出用户行为生成广告内容返回给浏览器。
3. Cookie的不足之处
-
Cookie容量小
浏览器对每个站点下的Cookie大小和数量都是有限制的。每个cookie的
name=value
的value值大概在4k
。 -
额外的性能开销
由于服务器设置 Cookie 后,浏览器的每次请求都会携带 Cookie 数据,会带来额外的性能开销。
4. 小结
Cookie是服务器返回并保存在浏览器本地的数据,浏览器下次请求时会自动带上Cookie信息。通常用来保持会话状态和跨站追踪。
但是Cookie并不适合存储复杂数据,因为其容量小且会产生性能开销。
二. Web Storage
1. 纯粹的客户端存储
过去,Cookie作为惟一的浏览器端存储方案,存储容量小且带来了额外的性能开销,并不适合所有的存储需求。更多时候,我们需要的是一个纯粹的客户端存储功能:即数据存储在浏览器端,不需要在浏览器和服务端之间来回传递。例如实现以下功能:
- 用户搜索历史记录功能。
- 存储客户端配置信息。
现在,Web Storage提供了更纯粹的浏览器端存储方案。
2. WebStorage是怎么实现的?
Web Storage通过创建一个Storage对象来存储键值对,key和value是字符串格式。并且该Storage对象只保存在浏览器本地,不会通过HTTP请求传递给服务端。
示例:
// 1.存储值
localStorage.setItem("key","value");
// 2.获取值
var valueLocal = localStorage.getItem("key");
// 3.删除值
Storage.removeItem("key");
// 4.清除Storage对象
Storage.clear();
// 5.Storage对象发送变化时,触发storage事件
window.addEventListener('storage', function(e) {
document.querySelector('.my-storage').textContent = e.storageArea;
});
a. 有效期
- sessionStorage :Storage对象仅在页面会话期间有效。
- localStorage :Storage对象是持久性的。在浏览器重新打开时依然有效。
b. 作用域
Web Storage也受同源策略保护。其中sessionStorage只作用于当前页面,即便打开两个标签页访问同一页面,也会创建两个不同的Storage对象。
c. 存储容量
Storage对象最大容量为5M左右。
3. 应用场景
Web Storage的应用场景:
-
localStorage实现用户搜索历史记录功能。
-
localStorage实现存储客户端配置信息。
-
sessionStorage可以作为会话级别的缓存,例如表单信息存储,实现刷新页面不丢失表单数据。
4. WebStorage的不足之处
- 只能存储字符串类型的数据,不支持其它数据类型。
- 存储容量只有5M左右。
- 数据是明文存储,且存在XSS攻击。
5. 小结
WebStorage是纯粹的客户端存储方案,可以满足大部分的存储需求。但面对专业性要求更高的存储需求时,依然存在不足,例如只支持字符串类型,存储容量不够大,数据是明文存储等。
三. IndexedDB
1. 更专业的数据存储
IndexedDB 是一个非关系型数据库,可以存储结构化克隆算法支持的任何对象(包括字符串、ArrayBuffer 对象和 Blob 对象等二进制数据)。支持索引检索。
使用过程包括:指定数据库模式,建立数据库连接,然后检索和更新一系列事务
。由于IndexedDB提供的是比较底层的api,所以开发中可以借助第三方库来操作。
四. 总结
- Cookie 解决的是HTTP协议无状态的问题;
- Web Storage 提供的纯浏览器端存储的功能,不涉及跟服务端交互;
- IndexedDB 是更专业的浏览器端存储方案,支持更大的存储容量,更复杂的数据结构。
正是有了这些更专业的浏览器端存储方案的出现,让Web应用的性能进一步的提升,可以承载更加复杂的业务功能。
参考资料
mdn
Cookie 已凉,Web 存储该这么做!