超越 Cookie:当今的客户端数据存储技术

超越 Cookie:当今的客户端数据存储

做者:Adam Giese

翻译:疯狂的技术宅javascript

原文:https://blog.logrocket.com/be...前端

未经容许严禁转载java

当 cookie 被首次引入时,它是浏览器保存数据的惟一方式。以后又有了不少新的选择:Web Storage API、IndexedDB 和 Cache API。那么 cookie 死了吗?咱们来看看这些在浏览器中存储数据的技术。git

Cookies

Cookie 是由服务器发送或在客户端上设置的信息单位,保存在用户的本地浏览器上。它们会自动附加到每一个请求上。因为 HTTP 是无状态协议,所以 cookie 容许将信息存储在客户端上,以便将其余上下文数据传给该服务器。程序员

Cookie 有一些标志,对于提升数据的安全性很是有用。 HttpOnly 标志阻止用 JavaScript 访问 cookie 的行为,只有附加在 HTTP 请求上时才能访问它们。这很是适合防止经过 XSS(跨站点脚本)攻击形成数据泄露。github

此外,Secure 标志确保仅在经过 HTTPS 协议发送请求时才发送 cookie。 SameSite 标志,能够设置为 laxstrict(它们的差别看这里),可用于帮助防止 CSRF(跨站点请求伪造)请求。它告诉浏览器只有在请求是与请求者在同一域中的 URL 时才发送 cookie。面试

何时使用 cookies?

那么,在哪些状况下你但愿得到 Cookie?最多见的应用场景之一是受权 token 。因为 HttpOnly 标志为 XSS 攻击添加了额外的保护层,SameSite 能够防止 CSRF,而 Secure 能够确保你的 cookie 被加密,这使你的身份验证token 有额外的保护层。算法

因为 auth token 很是小,所以你无需担忧请求过大。此外因为它们会自动附加到每一个请求,所以使用 cookie 能够在服务器上肯定用户是否通过身份验证。这对于服务器呈现的内容很是有用,例如你但愿将未通过身份验证的用户重定向到登陆页面。数据库

Cookie 的另外一个用途是存储用户的语言代码。因为你可能但愿在大多数请求中访问用户的语言,所以你能够利用它自动附加。apache

如何使用 cookies?

前面经讨论了要使用 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 上设置 SecureSameSite 标志,则能够执行如下操做:

document.cookie = 'product_ids=123,321;secure;samesite=lax'

因为 HTTPOnly 的做用是使 cookie 只能在服务器上访问,所以它只能由服务器添加。

除了这些安全标志以外,你还能够设置 Max-Age( cookie 应该保存的秒数)或 Expires(Cookie应该过时的日期)。若是这些都未设置,则 cookie 将跟随浏览器会话的持续时间。若是用户使用隐身模式,则会在用户会话关闭时删除 Cookie。

因为处理 cookie 的接口不是很友好,因此你可使用诸如 js-cookie 之类的库来方便对其的操做。

Web Storage API

Web Storage API 是一种在本地存储数据的新选项。它在 HTML5 中中添加,Web Storage API 包括localStoragesessionStorage。虽然 cookie 一般处理 server/client 通讯,但 Web Storage API 最适用于保存客户端数据。

咱们已经将 cookie 做为在本地存储数据的选项,为何还须要 Web 存储?其中一个缘由是:因为 cookie 会自动添加到每一个 HTTP 请求中,所以请求大小会变得臃肿。因此你能够用 Web Storage API 存储比 cookie 更大量的数据。

另外一个优势是更直观的 API。若是使用 cookie,你须要手动解析 cookie 字符串来访问各个键。 Web Storage 使这更加容易。若是要设置或获取值,可使用 setItemgetItem

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 上获得支持

那么localStoragesessionStorage 之间有什么区别呢?与 cookie 不一样,Web Storage API 没有过时或最大期限功能。若是使用 localStorage,除非手动删除,不然数据将无限期保留。你能够经过运行 localStorage.removeItem('key') 来删除单个键的值,或者经过运行 localStorage.clear() 清除全部数据。

若是使用 sessionStorage,则数据将仅持续到当前会话结束。若是你没有设置最大时间或过时,它将被视为与 cookie 保持的方式类似。在任何一种状况下,若是用户使用隐身,本地存储都不会在会话之间保留数据。

IndexedDB

若是 cookie 和 localStorage 都不符合你的要求,还有另外一种选择:IndexedDB,一个浏览器内置的数据库系统。

localStorage 同步执行全部方法时,IndexedDB 会异步调用它们。这将会容许访问数据而不会阻塞其他代码。当你处理大量可能访问代价高昂的代码时,这很是有用。

IndexedDB 在其存储的数据类型方面也具备更大的灵活性。虽然 cookies 和 localStorage 仅限于存储字符串,但 IndexedDB 能够存储能够经过“结构化克隆算法”复制的任何类型的数据。这包括 ObjectDateFileBlobRegEx 以及更多类型

性能和灵活性增长的缺点是 IndexedDB 的 API 更低级且更复杂。幸运的是有许多库能够解决这个问题。

localForage 为 IndexedDB 提供了一个更简单的相似 localStorage 的 API。 PouchDB 提供了一个能够离线的存储 API,能够与在线 CouchDB 数据库同步。 idb 是一个小型库,具备更简单的基于 promise 的 API。 Dexie 添加了更强大的查询 API,同时保持了良好的性能。根据你的使用状况还有许多选择。

Cache API

另外一种用于持久数据的专用工具是 Cache API。虽然它最初是为 service workers 建立的,但它可用于缓存任何网络请求。 Cache API 公开了 Window.caches,它提供了保存和检索响应的方法,容许你保存可永远之后访问的 RequestsResponses 对。

例如,若是你想在从 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 文档来获取更多信息:


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章:


相关文章
相关标签/搜索