浏览器端常用的存储技术及使用场景(重点)
浏览器端常用的存储技术是 Cookie、LocalStorage、SessionStorage。
(一)Cookie
Cookie 是最早被提出来的本地存储方式,在此之前,服务端是无法判断网络中的两个请求是否是同一用户发起的,为解决这个问题,Cookie 就出现了。
Cookie 是一种纯文本文件,每次发起 HTTP 请求都会携带 Cookie。
特性
- Cookie 一旦创建成功,名称就无法修改。
- Cookie 是无法跨域名的,也就是说 a 域名和 b 域名下的 Cookie 是无法共享的,这也是由 Cookie 的隐私安全性决定的,这样就能够阻止非法获取其他网站的 Cookie。
- 每个 Cookie 的大小限制在 4KB 左右,且由于 HTTP 请求头大小的限制,通常不建议存储超过几十个 Cookie。
- 有安全问题,如果 Cookie 未设置 HttpOnly,一旦页面存在 XSS 漏洞,攻击者就可以通过脚本读取 Cookie 并发送到自己的服务器,从而实现会话劫持。即使 Cookie 内容被加密(例如使用服务端加密的 Token),攻击者也可以原样转发该 Cookie 进行攻击,因此单纯依赖内容加密无法防御 XSS 窃取。正确做法是始终为认证相关的 Cookie 设置 HttpOnly,使其无法被 JavaScript 访问。
- Cookie 在请求一个新的页面的时候都会被发送过去。
在跨域域名之间共享 Cookie 的方法
- 使用 Nginx 反向代理:通过反向代理将不同域名的请求转发到同一域名下,从而实现 Cookie 共享。
- document.domain 方法:适用于子域名之间共享 Cookie,将不同子域名的 document.domain 设置为相同的主域名。
- postMessage 方法:适用于不同域名之间通过消息传递共享数据,结合 LocalStorage 实现跨域数据共享。
- 第三方 Cookie 配置:通过设置 SameSite=None 和 Secure 属性,允许第三方 Cookie 在跨域场景下使用。
- 服务端共享 session:在一个站点登录后,当浏览器访问其他站点时,由这些站点的服务端根据共享的 session 数据自行写入本域 Cookie。
使用场景
- 最常见的使用场景,就是 Cookie 和 session 结合使用,我们将 sessionId 存储到 Cookie 中,每次发请求都会携带这个 sessionId,这样服务端就知道是谁发起的请求,从而响应相应的信息。
- 统计页面的点击次数,网页端或者服务端将页面访问次数存入 Cookie。
(二)LocalStorage
LocalStorage 是 HTML5 新引入的特性,有时候我们存储的信息较大,Cookie 就不能满足我们的需求,这时候 LocalStorage 就派上用场了。
优点
- 在大小方面,LocalStorage 的大小一般为 5MB(不同浏览器可能有所不同,通常在 5MB 到 10MB 之间),可以储存更多的信息。
- LocalStorage 是持久储存,并不会随着页面的关闭而消失,除非主动清理,不然会永久存在。
- 仅储存在本地,不像 Cookie 那样每次 HTTP 请求都会被携带。
缺点
- 存在浏览器兼容问题,IE8 以下版本的浏览器不支持。
- 如果浏览器设置为隐私模式,那我们将无法读取到 LocalStorage。
- LocalStorage 受到同源策略的限制,即协议、主机地址、端口号三者必须完全一致,否则无法访问。
// 协议
http:、https:、ftp:、file:、ws:(WebSocket)、wss:(安全的 WebSocket)
// 主机地址
example.com
example.com 与它的实际IP地址(如 93.184.216.34)在浏览器的同源策略下被视为不同源,
因为同源策略比较的是主机地址的字符串表示,而不会尝试解析域名与IP地址的对应关系
// 端口
8080
使用场景
- 有些网站有换肤功能,这时候就可以将换肤的信息存储在本地的 LocalStorage 中,当需要换肤的时候,直接操作 LocalStorage 即可。
- 在网站中的用户浏览信息也会存储在 LocalStorage 中,还有网站的一些不常变动的个人信息等也可以存储在本地的 LocalStorage 中。
// 保存数据到 LocalStorage(可能需要 JSON.stringify)
localStorage.setItem('key', 'value');
// 从 LocalStorage 获取数据(可能需要 JSON.parse)
let data = localStorage.getItem('key');
// 从 LocalStorage 删除保存的数据
localStorage.removeItem('key');
// 从 LocalStorage 删除所有保存的数据
localStorage.clear();
// 获取某个索引的 Key(类似于数组的索引访问,提供顺序遍历能力)
localStorage.key(index)
(三)SessionStorage
SessionStorage 和 LocalStorage 都是在 HTML5 才提出来的存储方案。
SessionStorage 主要用于临时保存同一窗口(或标签页)的数据,刷新页面时不会删除,关闭窗口或标签页之后将会删除这些数据。
与 LocalStorage 对比
- 都在本地进行数据存储。
- SessionStorage 也有同源策略的限制,但是 SessionStorage 有一条更加严格的限制,SessionStorage 只有在同一个浏览器的同一个标签页下才能够共享(通过 window.open 或 a 标签打开的新页可能共享,取决于浏览器实现)。
- 都不能被传统爬虫爬取:传统爬虫只能获取服务器返回的静态 HTML 页面,无法执行 JS,因此无法读取存储在 LocalStorage 和 SessionStorage 中的数据。
使用场景
由于 SessionStorage 具有时效性,所以可以用来存储一些网站的游客登录的信息,还有临时的浏览记录的信息。当关闭网站之后,这些信息也就随之消除了。
// 保存数据到 sessionStorage(可能需要 JSON.stringify)
sessionStorage.setItem('key', 'value');
// 从 sessionStorage 获取数据(可能需要 JSON.parse)
let data = sessionStorage.getItem('key');
// 从 sessionStorage 删除保存的数据
sessionStorage.removeItem('key');
// 从 sessionStorage 删除所有保存的数据
sessionStorage.clear();
// 获取某个索引的Key(类似于数组的索引访问,提供顺序遍历能力)
sessionStorage.key(index)
Cookie 有哪些字段,作用分别是什么?(重点)
Cookie 由以下字段组成:
-
Name:Cookie 的名称。
-
Value:Cookie 的值,对于认证 Cookie,value 值包括 Web 服务器所提供的访问令牌。
-
Size:Cookie 的大小。
-
Domain:可以访问该 Cookie 的域名,Cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的 Cookie。
当需要实现单点登录方案时,Cookie 的上述特性非常有用,然而也增加了 Cookie 受攻击的危险,比如攻击者可以借此发动会话定置攻击。因而,浏览器禁止在 Domain 属性中设置 .org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻击发生的范围。
-
Path:可以访问此 Cookie 的页面路径。比如 Domain 是 abc.com,path 是 /test,那么只有 /test 路径下的页面可以读取此 Cookie。
-
Secure:指定是否使用 HTTPS 安全协议发送 Cookie。
使用 HTTPS 安全协议,可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。
该方法也可用于 Web 站点的身份鉴别,即在 HTTPS 的连接建立阶段,浏览器会检查 Web 网站的 SSL 证书的有效性。
但是基于兼容性的原因(比如有些网站使用自签署的证书)在检测到 SSL 证书无效时,浏览器并不会立即终止用户的连接请求,而是显示安全风险信息,用户仍可以选择继续访问该站点。
-
HttpOnly:该属性用来设置 Cookie 能否通过脚本来访问,默认为空,即可以通过脚本访问。
在客户端是不能通过 JS 代码去设置一个 HttpOnly 类型的 Cookie 的,这种类型的 Cookie 只能通过服务端来设置。
该属性用于防止客户端脚本通过 document.cookie 属性访问 Cookie,有助于保护 Cookie 不被跨站脚本攻击窃取或篡改。
但是,HttpOnly 的应用仍存在局限性。一些浏览器可以阻止客户端脚本对 Cookie 的读操作,但允许写操作;此外大多数浏览器仍允许通过 XMLHTTP 对象读取 HTTP 响应中的 Set-Cookie 头。
-
SameSite:跨站携带策略,现代浏览器默认 Lax,有效防御 CSRF 攻击。
-
Expires/Max-age:Cookie 的超时时间。若设置其值为一个时间,那么当到达此时间后,此 Cookie 失效。
不设置的话默认值是 session,意思是 Cookie 会和 session 一起失效,当浏览器关闭(不是浏览器标签页,而是整个浏览器)后,此 Cookie 失效。
总结
服务器端可以使用 Set-Cookie 的响应头部来配置 Cookie 信息。
一条 Cookie 包括了 5 个属性值:Domain、Path、Secure、HttpOnly、Expires
- Domain 是域名,Path 是路径,Domain 和 Path 一起限制了 Cookie 能够被哪些 url 访问。
- Secure 规定了 Cookie 只能在确保安全(HTTPS)的情况下传输。
- HttpOnly 规定了这个 Cookie 只能被服务器访问,不能使用 JS 脚本访问。
- Expires 指定了 Cookie 失效的时间。
实践建议
- 认证相关的 Cookie 必须同时设置 Secure、HttpOnly、SameSite=Lax(或 Strict)。
- Cookie 单条大小限制约 4KB,单个域名下不宜超过 20~30 条(实际上总大小超限会导致请求头过大)。
- 跨域共享 Cookie 需配合 SameSite=None; Secure,并确保服务端支持 CORS 且 withCredentials=true。
Cookie、SessionStorage、LocalStorage 的区别(重点)
Cookie
最开始是服务器端用于记录用户状态的一种方式,由服务器设置,在客户端存储,然后每次发起同源请求时,发送给服务器端。
Cookie 最多能存储 4KB 数据,它的生存时间由 Expires 属性指定,并且 Cookie 只能被同源的页面访问共享。
注意,“同源”在 Cookie 中有一个重要的例外——Domain 和 Path 属性,Cookie 允许设置 Domain 为父域名,从而实现子域之间的共享;Path 可以设置只有在某个路径及其子路径下的页面才会携带此 Cookie。Domain 放宽了同源限制(允许子域),Path 进一步限制了 URL 路径。而 LocalStorage 和 SessionStorage 严格遵循同源策略,即使是子域也无法共享父域的存储数据(除非使用 postMessage 等跨域通信手段)。
SessionStorage
HTML5 提供的一种浏览器本地存储的方法,它借鉴了服务器端 session 的概念,代表的是一次会话中所保存的数据。
它一般能够存储 5M 或者更大的数据,在当前窗口关闭后就失效了,并且只能被同一个窗口的同源页面所访问共享。
LocalStorage
HTML5 提供的一种浏览器本地存储的方法,它一般也能够存储 5M 或者更大的数据。
和 SessionStorage 不同的是,除非手动删除它,否则它不会失效,并且 LocalStorage 也只能被同源页面所访问共享。
前端的存储方式(重点)
Cookie
在 HTML5 标准前本地储存的主要方式,优点是兼容性好,请求头自带 Cookie 方便,缺点是大小只有 4KB,自动请求头加入 Cookie 浪费流量,每个域名限制 20 个 Cookie,使用起来麻烦,需要自行封装。
Cookie 优化:尽量减少 Cookie 的大小和数量,避免在不必要的请求中携带 Cookie。
Cookie 安全:设置 Secure,防止传输过程中的 Cookie 劫持(如中间人攻击);设置 HttpOnly 属性,防止 XSS 攻击导致的 Cookie 劫持。
LocalStorage
HTML5 加入的以键值对(Key-Value)为标准的方式,优点是操作方便,永久性储存(除非手动删除),大小为 5M,兼容 IE8+。
LocalStorage 优化:避免存储大量数据,定期清理不再需要的数据。
LocalStorage 安全:避免存储敏感信息,如用户密码、银行卡号等。
SessionStorage
与 LocalStorage 基本类似,区别是 SessionStorage 当页面关闭后会被清理,而且与 Cookie、LocalStorage 不同,它不能在所有同源窗口中共享,是会话级别的储存方式。
IndexedDB
是被正式纳入 HTML5 标准的数据库储存方案,它是 NoSQL 数据库,用键值对进行储存,可以进行快速读取操作,非常适合 Web 场景,同时用 JS 进行操作会非常方便。
IndexedDB 优化:合理使用事务和索引,提高数据读写性能。
IndexedDB 安全:对敏感数据进行加密存储,防止数据泄露。
Web SQL
2010 年被 W3C 废弃的本地数据库数据存储方案,但是主流浏览器(火狐除外)都已经有了相关的实现,Web SQL 类似于 SQLite,是真正意义上的关系型数据库,用 SQL 进行操作,当我们用 JS 时要进行转换,较为繁琐。
虽然目前主流浏览器(除 Firefox 外)仍支持,但 W3C 已停止维护,新项目严禁使用,应该使用 IndexedDB。
浏览器本地存储技术总结
小型数据存储方案
- Cookie:适用于需要在客户端和服务器之间传递的少量数据(≤4KB)
- LocalStorage:适用于长期保存的非敏感数据(≤5MB)
- SessionStorage:适用于临时存储会话期间的数据(≤5MB)
大型数据存储方案
- IndexedDB:适用于存储大量结构化数据(≥250MB),支持事务、索引和查询
IndexedDB 的特点
键值对储存
IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JS 对象。对象仓库中,数据以“键值对”的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
异步
IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
支持事务
IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
同源限制
IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
储存空间大
IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
支持二进制储存
IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
总结
本文详细介绍了浏览器本地存储的几种主要方式,包括 Cookie、LocalStorage、SessionStorage 以及 IndexedDB。每种存储方式都有其独特的特点、适用场景和限制。
- Cookie 适用于需要在客户端和服务器之间传递的少量数据,如会话管理和用户跟踪。
- LocalStorage 适合存储需要长期保存的非敏感数据,如用户偏好设置和应用状态。
- SessionStorage 适用于临时存储会话期间的数据,如表单输入和临时状态。
- IndexedDB 则为大量结构化数据提供了高效的存储和检索能力,适合离线应用和复杂数据管理。
选择合适的存储方式取决于具体的应用场景和需求,开发者需要根据数据的大小、生命周期、安全性和访问模式来做出明智的选择。