做者:Adam Giese翻译:疯狂的技术宅javascript
原文:https://blog.logrocket.com/be...前端
未经容许严禁转载java
当 cookie 被首次引入时,它是浏览器保存数据的惟一方式。以后又有了不少新的选择:Web Storage API、IndexedDB 和 Cache API。那么 cookie 死了吗?咱们来看看这些在浏览器中存储数据的技术。git
Cookie 是由服务器发送或在客户端上设置的信息单位,保存在用户的本地浏览器上。它们会自动附加到每一个请求上。因为 HTTP 是无状态协议,所以 cookie 容许将信息存储在客户端上,以便将其余上下文数据传给该服务器。程序员
Cookie 有一些标志,对于提升数据的安全性很是有用。 HttpOnly
标志阻止用 JavaScript 访问 cookie 的行为,只有附加在 HTTP 请求上时才能访问它们。这很是适合防止经过 XSS(跨站点脚本)攻击形成数据泄露。github
此外,Secure
标志确保仅在经过 HTTPS 协议发送请求时才发送 cookie。 SameSite
标志,能够设置为 lax
或 strict
(它们的差别看这里),可用于帮助防止 CSRF(跨站点请求伪造)请求。它告诉浏览器只有在请求是与请求者在同一域中的 URL 时才发送 cookie。面试
那么,在哪些状况下你但愿得到 Cookie?最多见的应用场景之一是受权 token 。因为 HttpOnly
标志为 XSS 攻击添加了额外的保护层,SameSite
能够防止 CSRF,而 Secure
能够确保你的 cookie 被加密,这使你的身份验证token 有额外的保护层。算法
因为 auth token 很是小,所以你无需担忧请求过大。此外因为它们会自动附加到每一个请求,所以使用 cookie 能够在服务器上肯定用户是否通过身份验证。这对于服务器呈现的内容很是有用,例如你但愿将未通过身份验证的用户重定向到登陆页面。数据库
Cookie 的另外一个用途是存储用户的语言代码。因为你可能但愿在大多数请求中访问用户的语言,所以你能够利用它自动附加。apache
前面经讨论了要使用 cookie 的缘由,如今来看看你能够如何使用 cookie。要从服务器上给客户端设置 cookie,须要在 HTTP 响应中添加 Set-Cookie
标头。 Cookie 应采用 key=value
的格式。若是你要在 Node.js 程序中设置 cookie,你的代码可能像下面这样:
response.setHeader('Set-Cookie', ['user_lang=en-us', 'user_theme=dark_mode']);
这将会设置两个 cookie:它将 user_lang
设置为 en-us
,将 user_theme
设置为 dark_mode
。
Cookie 也能够由客户端操纵。要设置 cookie,能够用 key=value
的格式为 document.cookie
赋值。若是 key 已存在,则会被覆盖掉。
document.cookie = 'user_lang=es-es';
若是已经定义了 user_lang
,它如今等于es-es
。
你能够经过访问 document.cookie
值来查看全部的 cookie。这将返回一串以分号作分隔的键值对。
document.cookie = 'user_lang=en-us'; document.cookie = 'user_theme=light_mode'; console.log(document.cookie); // 'user_lang=en-us; user_theme=light_mode;'
要增长键值对的可访问性,可使用如下函数将此字符串解析为对象:
const parseCookies = x => x .split(';') .map(e => e.trim().split('=')) .reduce((obj, [key, value]) => ({...obj, [key]: value}), {});
If you need to set one of the flags onto your cookie, you can add them after a semicolon. For example, if you’d like to set the Secure
and SameSite
flags onto your cookie, you would do the following:
若是你须要将其中一个标志设置到 cookie 上,能够在分号后添加它们。例如你想在 Cookie 上设置 Secure
和 SameSite
标志,则能够执行如下操做:
document.cookie = 'product_ids=123,321;secure;samesite=lax'
因为 HTTPOnly
的做用是使 cookie 只能在服务器上访问,所以它只能由服务器添加。
除了这些安全标志以外,你还能够设置 Max-Age
( cookie 应该保存的秒数)或 Expires
(Cookie应该过时的日期)。若是这些都未设置,则 cookie 将跟随浏览器会话的持续时间。若是用户使用隐身模式,则会在用户会话关闭时删除 Cookie。
因为处理 cookie 的接口不是很友好,因此你可使用诸如 js-cookie
之类的库来方便对其的操做。
Web Storage API 是一种在本地存储数据的新选项。它在 HTML5 中中添加,Web Storage API 包括localStorage
和 sessionStorage
。虽然 cookie 一般处理 server/client 通讯,但 Web Storage API 最适用于保存客户端数据。
咱们已经将 cookie 做为在本地存储数据的选项,为何还须要 Web 存储?其中一个缘由是:因为 cookie 会自动添加到每一个 HTTP 请求中,所以请求大小会变得臃肿。因此你能够用 Web Storage API 存储比 cookie 更大量的数据。
另外一个优势是更直观的 API。若是使用 cookie,你须要手动解析 cookie 字符串来访问各个键。 Web Storage 使这更加容易。若是要设置或获取值,可使用 setItem
或 getItem
。
localStorage.setItem('selected_tab', 'FAQ'); localSTorage.getItem('selected_tab'); // 'FAQ'
键和值都必须是字符串。若是你想保存一个对象或数组,能够在保存时调用 JSON.stringify()
并在读取时调用 JSON.parse()
来实现。
const product = { id: '123', name: 'Coffee Beans', }; localStorage.setItem('cached_product', JSON.stringify(product)); JSON.parse(localStorage.getItem('cached_product'));
local storage 的另外一个用例是在多个选项卡之间同步数据。经过为 'storage'
事件添加侦听器,你能够在另外一个选项卡或窗口中更新数据。
window.addEventListener('storage', () => { console.log('local storage has been updated'); });
仅当在另外一个文档中修改本地或会话存储时才会触发此事件。也就是说,你没法在当前浏览器选项卡中侦听 storage 的更改。不幸的是,截至撰写本文时,存储事件监听器还没有在 Chrome 上获得支持。
那么localStorage
和 sessionStorage
之间有什么区别呢?与 cookie 不一样,Web Storage API 没有过时或最大期限功能。若是使用 localStorage
,除非手动删除,不然数据将无限期保留。你能够经过运行 localStorage.removeItem('key')
来删除单个键的值,或者经过运行 localStorage.clear()
清除全部数据。
若是使用 sessionStorage
,则数据将仅持续到当前会话结束。若是你没有设置最大时间或过时,它将被视为与 cookie 保持的方式类似。在任何一种状况下,若是用户使用隐身,本地存储都不会在会话之间保留数据。
若是 cookie 和 localStorage
都不符合你的要求,还有另外一种选择:IndexedDB,一个浏览器内置的数据库系统。
当 localStorage
同步执行全部方法时,IndexedDB 会异步调用它们。这将会容许访问数据而不会阻塞其他代码。当你处理大量可能访问代价高昂的代码时,这很是有用。
IndexedDB 在其存储的数据类型方面也具备更大的灵活性。虽然 cookies 和 localStorage
仅限于存储字符串,但 IndexedDB 能够存储能够经过“结构化克隆算法”复制的任何类型的数据。这包括 Object
、 Date
、 File
、 Blob
、 RegEx
以及更多类型。
性能和灵活性增长的缺点是 IndexedDB 的 API 更低级且更复杂。幸运的是有许多库能够解决这个问题。
localForage
为 IndexedDB 提供了一个更简单的相似 localStorage
的 API。 PouchDB 提供了一个能够离线的存储 API,能够与在线 CouchDB 数据库同步。 idb 是一个小型库,具备更简单的基于 promise 的 API。 Dexie 添加了更强大的查询 API,同时保持了良好的性能。根据你的使用状况还有许多选择。
另外一种用于持久数据的专用工具是 Cache API。虽然它最初是为 service workers 建立的,但它可用于缓存任何网络请求。 Cache API 公开了 Window.caches
,它提供了保存和检索响应的方法,容许你保存可永远之后访问的 Requests
和 Responses
对。
例如,若是你想在从 API 请求响应以前检查浏览器的缓存以获取响应,则能够执行如下操做:
const apiRequest = new Request('https://www.example.com/items'); caches.open('exampleCache') // opens the cache .then(cache => { cache.match(apiRequest) // checks if the request is cached .then(cachedResponse => cachedResponse || // return cachedReponse if available fetch(apiRequest) // otherwise, make new request .then(response => { cache.put(apiRequest, response); // cache the response return response; }) }) .then(res => console.log(res)) })
第一次运行代码时,它将缓存响应。随后每次都会缓存请求,而且不会发出网络请求。
在浏览器上存储数据的每种方法都有其本身的用途。若是信息很小,很敏感,而且可能在服务器上使用,那么 cookie 就是最佳选择。若是要保存更大且更不敏感的数据,Web Storage API 多是更好的选择。
若是你打算存储大量结构化数据,IndexedDB 很是棒。 Cache API 用于存储来自 HTTP 请求的响应。根据你的须要,有不少工具可供使用。
你能够经过阅读 MDN 文档来获取更多信息: