Cookie
概述
2024年10月13日
- Cookie是最古老和最基本的客户端存储机制之一。
- Cookie是由服务器发送到用户浏览器的小型文本文件,存储在用户的计算机上。
- Cookie是基于域的,不区分协议
- 每次发送HTTP请求时,浏览器都会将相应的Cookie发送回服务器。
- Cookie通常用于存储用户偏好设置、跟踪用户行为等信息。
限制
- 格式:
name=value
, name和value都应该使用内建的 encodeURIComponent 函数对其进行转义 - 大小: encodeURIComponent 编码后的 name=value 对,大小不能超过 4KB
- 数量: 每个域的 cookie 总数在20到50左右,具体限制取决于浏览器。
- 可以通过设置Cookie的过期时间来控制Cookie的生命周期。
安全性
path=/mypath
:- 该路径下的页面可以访问该 cookie
- 默认为当前路径
domain=site.com
:- 控制可访问 cookie 的域
- 默认(也就是不设置的话),不会共享给子域
- 只有明确地将 domain 选项设置为根域,子域才能访问
// 在 site.com // 使 cookie 可以被在任何子域 *.site.com 访问: document.cookie = "user=John; domain=site.com" // 之后 // 在 forum.site.com alert(document.cookie); // 有 cookie user=John
expires
,max-age
- 如果没有设置这两个参数都没有设置,那么在关闭浏览器之后会消失,也就是
session cookie
expires
要求使用 GMT 时区的这种格式// 当前时间 +1 天 let date = new Date(Date.now() + 86400e3); date = date.toUTCString(); document.cookie = "user=John; expires=" + date;
max-age
: 单位为秒
- 如果没有设置这两个参数都没有设置,那么在关闭浏览器之后会消失,也就是
secure
- 表示该cookie只能通过HTTPS传输
samesite
strict
- 默认
- 如果用户来自同一网站之外,那么设置了 samesite=strict 的 cookie 永远不会被发送
lax
- 和 strict 模式类似,当从外部来到网站,则禁止浏览器发送 cookie,除非满足两个条件
- HTTP 方法是“安全的”(例如 GET 方法,而不是 POST)。
- 该操作执行顶级导航(更改浏览器地址栏中的 URL)。
- 缺点:会被到 2017 年左右的旧版本浏览器忽略(不兼容)
httpOnly
- Web服务器使用 Set-Cookie header 来设置 cookie时,可以设置 httpOnly 选项
- 禁止任何 JavaScript 访问 cookie
第三方cookie
- 如果 cookie 是由用户所访问的页面的域以外的域放置的,则称其为第三方 cookie。
- 通常用于跟踪和广告服务。它们被绑定在原始域上,因此第三方网站可以在不同网站之间跟踪同一用户,如果这些网站都可以访问该第三方网站的话
GDPR
- 欧洲有一项名为 GDPR 的立法,该法规针对网站尊重用户实施了一系列规则。其中之一就是需要明确的许可才可以跟踪用户的 cookie。
- 如果我们要设置带有身份验证会话(session)或跟踪 id 的 cookie,那么必须得到用户的允许。
参考
sessionStorage和localStorage
sessionStorage
- sessionStorage是HTML5引入的Web存储机制之一,用于在浏览器中临时存储会话数据。
- sessionStorage中存储的数据仅在当前会话期间有效,当用户关闭浏览器标签页或窗口时会被清除。
- sessionStorage中存储的数据仅限于当前页面或同源页面之间共享,不同页面之间的sessionStorage数据不会共享。
localStorage
- localStorage也是HTML5引入的Web存储机制之一,用于在浏览器中持久存储数据。
- localStorage中存储的数据在用户关闭浏览器后仍然保留,直到用户显式删除它们。
- localStorage中存储的数据也只限于同源页面之间共享,不同源页面之间的localStorage数据不会共享。
- 存满了会报错:
QuotaExceededError
对比
- 生命周期:
- Cookie可以通过设置过期时间来控制生命周期
- sessionStorage的数据仅在当前会话期间有效
- localStorage的数据则在浏览器关闭后仍然保留。
- 数据共享:
- Cookie的数据则在同源或跨域请求中都会发送到服务器端。
- sessionStorage: 多窗口之间sessionStorage不可以共享状态,但是在某些特定场景下新开的页面会复制之前页面的sessionStorage
- localStorage的数据在同源页面之间共享
- 存储容量:
- Cookie相对较小(几kb)
- sessionStorage和localStorage通常具有更大的存储容量限制(几兆)
storage event
不会冒泡
The storage event of the Window interface fires when a storage area (localStorage or sessionStorage) has been modified in the context of another document.
A way for other browsing contexts on the domain using the storage to sync any changes that are made.
Event properties
- key
- newValue
- oldValue
- storageArea
- url
示例
window.addEventListener("storage", () => { // When local storage changes, dump the list to // the console. console.log(JSON.parse(window.localStorage.getItem("sampleList"))); });
延伸
- use localStorage to maintain state across windows
- 使用sessionStorage和localStorage来存储jwt
- localStorage 存满了再往里写会发生什么?
- 存不进去并报错(QuotaExceededError)
- localSto存不进去并报错(QuotaExceededError)rage 存满了怎么办? - {Bison} - 博客园
参考:
- 请描述 cookie, sessionStorage 和 localStorage 的差异|ExplainThis
- Window.sessionStorage - Web API 接口参考 | MDN
- 面试官:你确定多窗口之间sessionStorage不能共享状态吗???🤔 - 掘金
IndexedDB
概念
- 浏览器中的数据库
用户能修改吗?
- 答: Chrome浏览器并没有提供给用户直接修改的方式,但肯定能改。
- 存储的位置位于(win11系统):
c:\Users\USERNAME\AppData\Local\Google\Chrome\User Data\Default\IndexedDB\
- 每个“源”有两个文件夹,类似于ps: 看到这就很好理解同源的要求了
http_localhost_3001.indexeddb.blob http_localhost_3001.indexeddb.leveldb https_www.bilibili.com_0.indexeddb.blob https_www.bilibili.com_0.indexeddb.leveldb
- 被加密了,但还是不推荐存储任何服务端敏感的内容于用户端
- Edit IndexedDB data by using the Console tool - Microsoft Edge Developer documentation | Microsoft Learn
优化
- 思路来自Tristan on X
虽然indexDB可以当数据库存很多图片(blob),但随着用户使用的时间变长,本地存放的图会越来越多,其实大部分是不会再用到的,数据一多,读取效率会打折扣,所以做了个FIFO存储队列,最多存50张。
参考
- IndexedDB - Web API 接口参考 | MDN
- IndexedDB
- Edit data in IndexedDB by the user - Stack Overflow
- View and change IndexedDB data - Microsoft Edge Developer documentation | Microsoft Learn
CacheStorage
- This feature is available in Web Workers.
参考
浏览器缓存
定义
当我们访问一个网站时,会加载各种资源,如 HTML文档、JS、CSS、图片等。浏览器会将一些不经常变的资源保存在本地,这样下次访问相同网站时,就直接从本地加载资源,并不通过请求服务器,这就是浏览器缓存
分类
根据位置分类
- memory cache:主要用来缓存有 preloader 相关指令的资源;关闭tab页后就释放
- disk cache
根据是否需要和服务器进行通信分类
- 强缓存
- 不会向服务器发送请求,直接从缓存中读取资源
- 通过
Expires
和Cache-Control
来实现的
- 协商缓存
- 在强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识来决定是否使用缓存
- 利用的是
Last-Modified
,If-Modified-Since
和ETag
,If-None-Match
这两对Header来管理
- 强缓存
Response Header中的相关属性
Expires
- HTTP/1
Last-Modified
/If-Modified-Since
- HTTP/1
- 流程
- 浏览器第一次访问资源,服务器会 Response Header 里添加 Last-Modified 的值
- 浏览器在下一次请求这个资源的时候,检测到有
Last-Modified
这个 Header。浏览器就会在Request中加上If-Modified-Since
,If-Modified-Since
的值就是 Last-Modified 的值 - 服务器收到请求后,如果资源没有修改,服务器返回 304 Not Modified 状态码,并且不包含资源的内容。浏览器此时会使用本地缓存中的资源。
- 如果资源发生了修改,服务器会返回新的资源内容和更新后的 Last-Modified。
Cache-Control
- HTTP/1.1
- 优先级比 Expires 要高
- 可选值
- public
- private
- no-store: 完全禁用缓存,资源不会存储在缓存中。
- no-cache: 告诉浏览器要使用缓存文件,但是每次需要跟服务器确认是最新文件以后才能用,一般使用 Etag 或者 Last-Modified 字段来控制缓存
- max-age=60
ETag
/If-None-Match
- HTTP/1.1
- ETag由服务器生成,三种方式:基于内容 / 基于版本 / 自定义生成
- 浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的
Etag
值放到request header里的If-None-Match
里 - ETag 的优先级要高于 Last-Modified
- 解决了
Last-Modified
的如下问题- 某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。
- 某些文件的修改非常频繁,在秒以下的时间内进行修改. Last-Modified只能精确到秒。
- 一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。
如何禁用缓存(如何使缓存失效)
- 场景一: 发版,要求无视缓存
- 每次对应静态文件里有内容改动的时候,自动加一段 hash 到静态文件名里
- 场景二: 用户自己想要刷新
- F5 刷新: 因浏览器而异
- Ctrl + F5 强制刷新的时候,会暂时禁用强缓存和协商缓存
后端配置
setHeader
之类- Nginx 配置
参考
- 浏览器缓存机制:强缓存和协商缓存
- 前端 - 浏览器的强缓存和协商缓存 - yiliang.share - SegmentFault 思否
- HTTP缓存控制: Cache-Control - Lewin’s Blog
其他缓存
Memory Cache(内存缓存)
- 特点:缓存存储在浏览器的内存中,主要用于存储从网络请求获取的资源(如 HTML、CSS、JavaScript 和图片)。这种缓存生命周期短,只在当前页面会话中有效,页面刷新或关闭后缓存会被清除。
- 用途:用于快速重用同一页面内的资源,提升页面加载速度。
- 存储时间:通常在页面刷新或关闭后即清除。
- 优点:速度最快,适用于瞬时的页面资源重用。
Push Cache
- 特点: 在用户并未明确请求某些资源的情况下,提前将这些资源推送到用户的缓存中。
- 用途: 在用户即将需要某些资源时,提前发送这些资源,这样在用户实际请求时,可以直接从缓存中获取,而无需再次请求服务器。
Application Cache(AppCache)
- 特点:这是 HTML5 中引入的离线缓存机制,允许开发者为 web 应用创建一个离线模式,用户即使断网也能访问缓存的内容。然而,由于 AppCache 有不少缺陷和安全隐患,已被弃用。
- 用途:过去用于创建离线 web 应用,但目前已被
Service Worker
取代。 - 状态:AppCache 从 HTML 5.1 开始废弃,现在大多数浏览器都不再支持。
WebSQL
- 特点:WebSQL 是一种基于 SQL 的数据库,最初用于在浏览器中存储结构化数据。然而由于其标准化进程停止,WebSQL 不再是主流推荐的方案。
- 用途:在浏览器中进行 SQL 查询和存储结构化数据,类似
IndexedDB
的早期版本。 - 状态:已被
IndexedDB
取代。
Web Storage Cache API
- 特点:缓存 API 是
Service Worker
的一部分,允许在浏览器中存储Request
和Response
对象,常用于离线缓存。与普通缓存机制不同,开发者可以精确控制缓存的资源,并且缓存的内容可以在离线时访问。 - 用途:用于离线支持、缓存管理、动态内容缓存,通常与
Service Worker
配合使用。 - 优点:可控性更强,适用于现代 PWA(渐进式 Web 应用)的缓存策略。
Manifest Storage
- 特点:一种较新的 API(如 Web App Manifest),允许开发者为应用程序提供缓存策略和应用图标等元数据,常用于渐进式 Web 应用(PWA)。
- 用途:存储应用元数据,定义应用行为(如是否作为全屏应用、离线模式等)。
File System Access API
- 特点:允许 Web 应用访问用户的文件系统,可以直接读写文件。通过这个 API,Web 应用可以处理用户计算机上的文件,实现类似桌面应用的体验。
- 用途:用户可以在不离开浏览器的情况下,直接从文件系统中读取、修改和保存文件。
- 状态:这是一个较新的 API,仍在部分浏览器中实现,安全性要求较高。