10 浏览器存储
10.1 localStorage
localStorage 是浏览器提供的一种存储数据的机制,可以用于在客户端(浏览器)保存数据,即使用户关闭浏览器后再次打开也能够保持数据的存在。 localStorage 可以存储的数据类型有限,只能存储字符串类型的数据。如果需要存储其他类型的数据,可以通过 JSON.stringify() 将其转换为字符串,再通过 JSON.parse() 将其转换回原来的类型。 下面是一些 localStorage 常用的方法:
- 存储数据
localStorage.setItem('key', 'value');该方法可以将键值对存储到 localStorage 中。如果 key 已经存在,则会覆盖原来的值。 - 获取数据
var value = localStorage.getItem('key');该方法可以根据键获取存储在 localStorage 中的值。 - 移除数据
localStorage.removeItem('key');该方法可以根据键移除 localStorage 中的数据。 - 清空数据
localStorage.clear();该方法可以清空 localStorage 中的所有数据。 - 监听数据变化
window.addEventListener('storage', function(event) {
console.log(event.key + ' has been changed from ' + event.oldValue + ' to ' + event.newValue);
});
当另一个窗口修改了 localStorage 中的数据时,该事件将在当前窗口中触发。在事件处理程序中,可以获取修改的键、旧值和新值。
- 容量限制 localStorage 的最大容量是不同浏览器之间会有所不同,但通常都是 5-10 MB。这个容量是针对每个域名的,每个域名只能使用自己的 localStorage。 localStorage 存储的数据是永久的,除非手动清除,否则数据将一直存在于客户端中。此外,由于 localStorage 存储的数据只能是字符串类型,所以需要在存储和获取数据时进行类型转换。
- 同域限制 localStorage 的作用域是针对每个域名的,也就是说,只有在同一个域名下的页面才可以共享同一份 localStorage 数据。换句话说,只有在同一域名下的页面之间才能访问同一份 localStorage 数据。 比如,假设网站 A 的域名是 example.com,那么在 example.com 域名下的所有页面都可以访问同一份 localStorage 数据。但如果页面跳转到了网站 B 的域名 example.org 下,那么 example.org 下的页面就无法访问 example.com 下的 localStorage 数据。 需要注意的是,在同一个域名下的不同子域名之间,也无法直接访问 localStorage 数据。比如,www.example.com 和 blog.example.com 是两个不同的子域名,它们之间也不能直接访问 localStorage 数据。
10.2 sessionStorage
sessionStorage 是 HTML5 新增的客户端存储方案之一,它与 localStorage 相似,都是用于在客户端存储数据的对象。不同的是,sessionStorage 中存储的数据仅在当前会话中有效,即只要浏览器窗口没有关闭,数据就一直存在;而一旦关闭浏览器窗口,存储的数据就会被清除。
下面是 sessionStorage 的使用方法:
1 存储数据:
// 存储字符串数据
sessionStorage.setItem('key', 'value');
// 存储对象数据,需要先将对象转换为字符串
var obj = { name: 'John', age: 18 };
sessionStorage.setItem('key', JSON.stringify(obj));
2 获取数据:
// 获取字符串数据
var value = sessionStorage.getItem('key');
// 获取对象数据,需要将字符串转换为对象
var obj = JSON.parse(sessionStorage.getItem('key'));
3 删除数据:
sessionStorage.removeItem('key');
4 清空所有数据:
sessionStorage.clear();
需要注意的是,sessionStorage 中存储的数据仅在当前会话中有效,即只要浏览器窗口没有关闭,数据就一直存在。如果在当前窗口中打开了多个标签页,那么它们共享同一份 sessionStorage 数据。但是,如果在打开的标签页中使用了 window.open() 方法打开了一个新的窗口,那么新窗口将会拥有一个全新的 sessionStorage 对象。
另外,需要注意的是,由于 sessionStorage 存储的数据仅在当前会话中有效,因此它不适用于长期存储数据。如果需要在客户端长期存储数据,可以使用 localStorage,或者其他的客户端存储方案,比如 IndexedDB。
10.3 IndexDB
IndexedDB 是 HTML5 新增的客户端存储数据库,它是一种 NoSQL 数据库,可以在客户端存储大量结构化数据,并且支持高效的数据检索和索引。IndexedDB 在浏览器中运行,可以用来存储应用程序的离线数据,或者用作客户端缓存,以提高应用程序的性能。 IndexedDB 的主要特点包括: 1 支持事务处理:可以在 IndexedDB 中执行多个操作,并保证这些操作都在一个事务中执行。这样可以保证在执行这些操作时,数据库的状态始终是一致的。 9 支持异步操作:IndexedDB 的所有操作都是异步执行的,这样可以避免阻塞浏览器的主线程,提高应用程序的性能。 10 支持数据检索和索引:IndexedDB 支持数据的快速检索和索引,可以根据指定的键或索引来查询数据。 下面是 IndexedDB 的一些常用 API:
- 打开数据库:
var request = indexedDB.open('myDatabase', 1);
request.onsuccess = function(event) {
var db = event.target.result;
// do something with the database
}
2.创建对象仓库:
var objectStore = db.createObjectStore('myObjectStore', { keyPath: 'id' });
objectStore.createIndex('name', 'name', { unique: false });
3.添加数据:
var transaction = db.transaction(['myObjectStore'], 'readwrite');
var objectStore = transaction.objectStore('myObjectStore');
var request = objectStore.add({ id: 1, name: 'John' });
request.onsuccess = function(event) {
console.log('Data added successfully');
}
4.更新数据
var transaction = db.transaction(['myObjectStore'], 'readwrite');
var objectStore = transaction.objectStore('myObjectStore');
var request = objectStore.put({ id: 1, name: 'Mike' });
request.onsuccess = function(event) {
console.log('Data updated successfully');
}
5.删除数据:
var transaction = db.transaction(['myObjectStore'], 'readwrite');
var objectStore = transaction.objectStore('myObjectStore');
var request = objectStore.delete(1);
request.onsuccess = function(event) {
console.log('Data deleted successfully');
}
6.查询数据:
var transaction = db.transaction(['myObjectStore'], 'readonly');
var objectStore = transaction.objectStore('myObjectStore');
var request = objectStore.get(1);
request.onsuccess = function(event) {
var data = event.target.result;
console.log(data);
}
需要注意的是,IndexedDB 的 API 比较复杂,使用起来也比较麻烦。为了方便开发,可以使用一些 IndexedDB 的封装库,比如 Dexie.js 和 IDBWrapper。这些库可以简化 IndexedDB 的使用,并提供更友好的 API。
10.4 cookie
document.cookie
JavaScript 通过 document.cookie 属性提供了操作 cookie 的接口。
设置 cookie
要设置一个新的 cookie,可以直接给 document.cookie 赋一个字符串,格式为 name=value; expires=expiration_time; path=path_value; domain=domain_value; secure。
其中:
1 name 表示 cookie 的名称,必填项。
2 value 表示 cookie 的值,必填项。
3 expires 表示 cookie 的过期时间,可以是一个日期对象、一个 GMT 格式的字符串或一个以秒为单位的数值。如果不设置该属性,那么 cookie 将在浏览器关闭时失效。
4 path 表示 cookie 的作用路径,默认为当前路径。只有路径与当前页面路径匹配的 cookie 才会发送到服务器。
5 domain 表示 cookie 的作用域,默认为当前域名。只有与当前域名匹配的 cookie 才会发送到服务器。
6 secure 表示 cookie 是否只能通过安全协议(如 HTTPS)来传输。
示例:
document.cookie = "name=value; expires=Thu, 22 Apr 2024 12:00:00 GMT; path=/; domain=.example.com; secure";
读取 cookie
可以通过 document.cookie 属性来读取当前页面的所有 cookie。返回的字符串是以分号加空格分隔的键值对列表。
示例:
console.log(document.cookie); // "name=value; other=value; ..."
为了获取某个特定的 cookie,需要写一个函数来解析 cookie 字符串。
function getCookie(name) {
const cookies = document.cookie.split("; ");
for (const cookie of cookies) {
const [cookieName, cookieValue] = cookie.split("=");
if (cookieName === name) {
return cookieValue;
}
}
return null;
}
console.log(getCookie("name")); // "value"
删除 cookie
要删除一个 cookie,可以通过将该 cookie 的过期时间设置为一个过去的时间来实现。
示例:
document.cookie = "name=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.example.com; secure";
Http协议中的Cookie
在 HTTP 协议中,Cookie 是一种用于在服务器和客户端之间传递信息的机制。客户端在访问服务器时,可以将包含一些数据的 Cookie 发送给服务器,服务器在接收到 Cookie 后就可以读取其中的数据,从而实现客户端和服务器之间的交互。
在 HTTP 协议中,Cookie 是通过 Set-Cookie 和 Cookie 头字段来实现的。服务器通过 Set-Cookie 头字段来设置 Cookie,客户端在发送请求时通过 Cookie 头字段来传递 Cookie。下面是一些常用的 Cookie 头字段的说明:
Set-Cookie:用于在服务器端设置 Cookie。其格式为 Set-Cookie: name=value; expires=expiration_time; path=path_value; domain=domain_value; secure。
Cookie:用于在客户端发送 Cookie。其格式为 Cookie: name1=value1; name2=value2; ...。
在设置 Cookie 时,常用的属性有 name、value、expires、path 和 domain。其中,name 和 value 属性用于设置 Cookie 的名称和值,expires 属性用于设置 Cookie 的过期时间,path 和 domain 属性用于设置 Cookie 的作用路径和作用域。
Cookie 的作用路径和作用域决定了该 Cookie 可以被哪些页面读取。如果不指定作用路径和作用域,那么默认情况下只有与设置该 Cookie 的页面在同一域名和路径下的页面才可以读取该 Cookie。如果指定了作用路径和作用域,那么只有在该路径和域名下的页面才可以读取该 Cookie。
需要注意的是,由于 Cookie 存储在客户端,因此存在安全问题。攻击者可以通过某些手段获取用户的 Cookie,从而冒充用户身份进行一些危险的操作。
HttpOnly 是一种用于增强 Cookie 安全性的属性,它可以防止客户端脚本(如 JavaScript)访问 Cookie。这样,即使攻击者能够通过某些方式获取到用户的 Cookie,也无法通过脚本获取其中的敏感信息,从而减少了攻击的风险。
HttpOnly 是通过在设置 Cookie 时添加一个 HttpOnly 属性来实现的。例如:
Set-Cookie: name=value; HttpOnly
需要注意的是,HttpOnly 只能防止客户端脚本访问 Cookie,但无法防止 CSRF(跨站请求伪造)攻击, 后边章节会展开讲解CSRF。为了防止 CSRF 攻击,通常还需要采取其他的防范措施,如使用随机的 CSRF Token、验证 Referer 等。