客户端存储和http缓存

通过本文学习,将获得以下知识:

1. web 端存储有哪些方式

2. 不同存储之间的区别,以及使用场景

3. http缓存有哪些策略

web 存储的由来

为什么需要 web 存储呢,也就是客户端存储,我们知道我们现在的项目大多数都是前端负责静态页面的展示,需要请求后端接口获得数据来完成页面的交互,所以这样很依赖后端服务,并且请求速度也是不可控的。

现代web浏览器提供了很多在用户电脑web客户端存放数据的方法 — 只要用户的允许 — 可以在它需要的时候被重新获得。这样能让你存留的数据长时间保存, 保存站点和文档在离线情况下使用, 保留你对其站点的个性化配置等等。

而且在某些场景下有些数据也不需要存储到后端,或者从后端请求过来的数据基本不会改变,那么浏览器也不必每次都去请求数据,可以节省资源。

客户端存储有哪些好处

  • 个性化网站偏好(比如显示一个用户选择的窗口小部件,颜色主题,或者字体)。
  • 保存之前的站点行为 (比如从先前的session中获取购物车中的内容, 记住用户是否之前已经登陆过)。
  • 本地化保存数据和静态资源可以使一个站点更快(至少让资源变少)的下载, 甚至可以在网络失去链接的时候变得暂时可用。
  • 保存web已经生产的文档可以在离线状态下访问。

客户端存储使用场景

  • 比如用户信基本信息,在前端页面展示中可能多处会使用到,以及作为参数传给后端,这时,可以保存在 客户端,根据需要随时可以取出。
  • 临时存储,根据需要,比如临时草稿,在页面期间存留,可以随时找回,这时,可以先存储到web端,方便使用。
  • 标记用户与跟踪用户行为的情况,推荐使用cookie
  • 适合长期保存在本地的数据(令牌),推荐使用localStorage
  • 敏感账号一次性登录,推荐使用sessionStorage
  • 存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB

web 端存储方式有哪些

《客户端存储和http缓存》

在浏览器中的控制台可以看到,web存储的方式有

  •  localStorage 、
  • sessionStorage 、
  • indexDB、
  • webSQL、
  • Cookies 

Cookies

cookies 是最老的一种存储方式,它的好处是兼容最老的浏览器,缺点就是已经过时,不太符合现代的需求,以及容易产生很多安全问题,实际中基本不会考虑使用。

使用方式:document.cookie

可以获取到所有的cookie,并且以分号的形式分离不同的cookie。

《客户端存储和http缓存》

《客户端存储和http缓存》

 存储大小和个数的限制

大小:最多4K

个数:

  • IE6及以下每个域名最多包含20个Cookie;
  • IE7及以上每个域名最多50个Cookie;
  • Firefox每个域名最多50个Cookie;
  • Opera下每个域名最多30个Cookie;
  • Sarafi和Chrome对每个域的Cookie数目没有严格限制。

读写数据方式

写入数据:

《客户端存储和http缓存》

读取数据:

《客户端存储和http缓存》

HTTP 请求中的cookie

在客户端和服务端进行通信的时候,如果服务端设置了cookie,服务器可以在响应头里面添加一个 Set-Cookie 选项。浏览器收到响应后通常会保存下 Cookie,之后对该服务器每一次请求中都通过  Cookie 请求头部将 Cookie 信息发送给服务器。另外,Cookie 的过期时间、域、路径、有效期、适用站点都可以根据需要来指定。

找了一个github里面的请求,在Response Header里面设置了 set-cookie信息:

《客户端存储和http缓存》

在 application cookie中可以看到

《客户端存储和http缓存》

 在 Request Header中 可以看到将这些cookie都放在了cookie中,并且传给后端

《客户端存储和http缓存》

 这会产生的缺点是,占据一定的带宽。而且cookie在传输的过程还存在一些风险,cookie的唯一性(是否可预测),完整性(是否被篡改),过期等校验。

可以看到cookie的几个属性:path=/; expires=Wed, 23 Mar 2022 03:23:22 GMT; secure; HttpOnly; SameSite=Lax,(Secure HttpOnly属性、Same-Site属性)

Secure Cookie机制指的是设置了secure标志的cookie。Secure Cookie仅在https层面上安全传输,如果是http请求,就不会带上这个cookie。

《客户端存储和http缓存》

 这样能降低重要的cookie被中间人截获的风险。
不过,也不是说可以万无一失。因为secure cookie对于客户端脚本来说是可读可写的,可读就意味着secure cookie能被盗取,可写意味着能被篡改,所以还是存在一定的风险。

Cookie的HttpOnly属性,指浏览器不要在除HTTP(和 HTTPS)请求之外暴露Cookie。

一个有HttpOnly属性的Cookie,不能通过非HTTP方式来访问,例如通过调用JavaScript(例如,引用document.cookie),因此,不可能通过跨域脚本(一种非常普通的攻击技术)来偷走这种Cookie。Facebook 和 Google 正在广泛地使用HttpOnly属性。

《客户端存储和http缓存》

可以看到我们使用document.cookie并不是查到所有的cookie,那些设置了httponly的cookie是获取不到的。

当用户从http://a.com发起http://b.com的请求也会携带上Cookie,而从http://a.com携带过来的Cookie称为第三方Cookie。
为了防止CSRF(Cross-site request forgrey)攻击,可以使用SameSite属性。

Set-Cookie: CookieName=CookieValue; SameSite=Lax; Set-Cookie: CookieName=CookieValue; SameSite=Strict;

  • strict:浏览器在任何跨域请求中都不会携带Cookie,这样可以有效的防御CSRF攻击,但是对于有多个子域名的网站采用主域名存储用户登录信息的场景,每个子域名都需要用户重新登录,造成用户体验非常的差。
  • lax:相比较strict,它允许从三方网站跳转过来的时候使用Cookie。

都说了cookie不重要,为啥还要讲那么多~

localStorage

用于存储和检索较小的、由名称和相应值组成的数据项。当您只需要存储一些简单的数据时,比如用户的名字,用户是否登录,屏幕背景使用了什么颜色等等,这是非常有用的。

localStorage 存储数据是一直保存数据,在不同的页面打开,甚至到浏览器关闭又开启后也是这样。当然不同的浏览器自然不能保存了(为每个域名分离存储)。

每个域都有一个单独的数据存储区(每个单独的网址都在浏览器中加载). 你 会看到,如果你加载两个网站(例如google.com和amazon.com)并尝试将某个项目存储在一个网站上,该数据项将无法从另一个网站获取。

这是有道理的 – 你可以想象如果网站能够查看彼此的数据,就会出现安全问题!

写入数据:

《客户端存储和http缓存》

读取数据:

《客户端存储和http缓存》

 移除数据:

《客户端存储和http缓存》

 我们可以发现 Storage 数据结构是有遍历器特点的,我们可以遍历 keys values 。

存储大小:5M

sessionStorage

和localStorage相比较,sessionStorage是存储在每个会话中的,当浏览器页面关闭即失效。

写入数据:

《客户端存储和http缓存》

《客户端存储和http缓存》 读取数据:

《客户端存储和http缓存》

 当关闭再打开,无了~

《客户端存储和http缓存》

 移除数据:

《客户端存储和http缓存》

存储大小:5M

http缓存

什么意思呢?白话一点讲就是我们缓存http请求返回的数据。http请求做为影响前端性能极为重要的一环,因为请求受网络影响很大,如果网络很慢的情况下,页面很可能会空白很久。对于首次进入网站的用户可能要通过优化接口性能和接口数量来解决。但是,对于重复进入页面的用户,除了浏览器缓存,http缓存可以很大程度对已经加载过的页面进行优化。

先放一张图:展示整改流程

《客户端存储和http缓存》

强缓存

浏览器在第一次访问接口后的response headers里会携带一些字段,这些字段决定关于这个请求的缓存情况,
与强缓存相关的header字段有两个:

1、expires:这是http1.0时的规范;它的值为一个绝对时间的GMT格式的时间字符串,如Mon, 10 Jun 2015 21:31:12 GMT,如果发送请求的时间在expires之前,那么本地缓存始终有效,否则就会发送请求到服务器来获取资源

2、cache-control:http1.1的规范:max-age=number,这是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对值;资源第一次的请求时间和Cache-Control设定的有效期,计算出一个资源过期时间,再拿这个过期时间跟当前的请求时间比较,如果请求时间在过期时间之前,就能命中缓存,否则就不行;
no-cache:不使用本地缓存。走协商缓存。

no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。

public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。

private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
  注意:如果cache-control与expires同时存在的话,cache-control的优先级高于expires

强缓存时段命中,会直接从缓存中返回数据,返回值200;这一时间段,不管接口内容有没有变化都不会进行请求更新。

协商缓存

当没有强缓存时,会向服务端寻求帮助,也就是问一下服务端有没有更改,向接口判断是否有缓存。如果命中协商缓存则返回304状态码,并且从本地返回缓存内容。如果没有命中,则重新发起请求。
协商缓存需要跟服务端通过特殊标示连接,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。

先来看看 etag的例子吧,选中下面这个例子分析下:

《客户端存储和http缓存》

 响应头返回了etag值,etag:”358-hAhEy1v13r0+M/D7Tn49MKIF0Hw。请求头里面并没有携带任何缓存标志。

《客户端存储和http缓存》

 下一步普通刷新请求,状态码返回304,响应头还是返回etag,请求携带if-none-match:”358-hAhEy1v13r0+M/D7Tn49MKIF0Hw”

《客户端存储和http缓存》

 《客户端存储和http缓存》

 可以发现这两个值并没有发生改变,请求的是缓存里面的。

下面再来看last-modified的例子:返回了last-modified 、catch-control、expires,那么正好来看下这几个的优先级。次数请求头没有任何关于缓存的标志。

《客户端存储和http缓存》

根据上门的流程图,我们也应该猜到先是强缓存>协商缓存,强缓存里面 cache-control>expires,所以先走的catch-control,然后cache-control:no-cache, no-store, must-revalidate,不使用本地缓存。走协商缓存。所以接下来走协商缓存了。表示这个资源在服务器上的最后修改时间Sun, 17 May 1998 03:00:00 GMT。哈哈,这里漏了一个属性,cache-control:no-cache, no-store, must-revalidate,也就是禁止缓存,所以我重新请求返回结果还是一样的200.

再找例子:

《客户端存储和http缓存》

这种是协商缓存的两种都使用了,其实不管先后顺序,因为它们的含义其他都差不多,代表是上次更改文件时间(hash代表上次文件hash),所以效果都一样的。 

    原文作者:阳阳C
    原文地址: https://blog.csdn.net/qq_40409143/article/details/123677429
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞