1.前端存储数据的好处

通过把数据存储在浏览器中,用户不必每次都向服务器请求获取同一个信息。甚至在离线的情况下,也可以获取本地存储的数据而不是通过服务端获取数据;
减少请求次数,减轻服务端压力;
数据随用随取,不用过度依赖于服务端;

2.前端需要存储什么数据

根据不同情况存储需要的数据,如用户的信息(用户名,用户id,用户身份等),需要保留的操作数据(如用户在某次选择中需要记录的数据)

3.前端存储的数据在哪里可以看到

image.png

4.前端存储数据的方式

  • Cookie
  • localStorage
  • sessionStorage
  • indexedDB

5.Cookie

1)什么是Cookie
当用户浏览器向服务器发送请求时,服务器会返回给用户浏览器一小块数据,用户浏览器会将这一小块数据存储在本地,在下一次向同一个服务器发起请求时会携带上这一小块数据,告知服务端这两个请求是否来自同一浏览器。值得一提的是,一开始Cookie被发明出来并不是为了给浏览器存储数据,而是为了解决http协议的无标记状态问题:用户的两次 HTTP 请求,服务端并不能通过请求本身,知道这两次请求,来自于同一个用户。
image.png
2)Cookie的组成

  • 名称:一个唯一确定cookie的名称
  • 值:存储在cookie中的字符串值,值必须被URL编码
  • 域:cookie对于哪个域是有效的,所有向该域发送的请求都会包含这个cookie信息
  • 路径:对于指定域中的路径,应该向服务器发送cookie
  • 失效时间:表示cookie何时应该被删除的时间戳

如:
username = Bill Gates
3)js创建Cookie

  1. //js创建Cookie
  2. document.cookie = "username=Bill Gates";
  3. document.cookie = "username=John Doe; expires=Sun, 31 Dec 2017 12:00:00 UTC";
  4. //js获取Cookie
  5. var x = document.cookie;
  6. //js删除Cookie
  7. //不用指定Cookie,直接将expires参数设置为过去的日期即可
  8. document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

例子:

  1. //设置Cookie
  2. function setCookie(cname, cvalue, exdays) {
  3. var d = new Date();
  4. d.setTime(d.getTime() + (exdays*24*60*60*1000));
  5. var expires = "expires="+ d.toUTCString();
  6. document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
  7. }
  8. // 清除cookie
  9. clearAllCookie: function () {
  10. var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
  11. if (keys) {
  12. for (var i = keys.length; i--;)
  13. document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString()
  14. }
  15. },
  16. //获取Cookie
  17. getCookie: function (name) {
  18. var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
  19. if (arr = document.cookie.match(reg))
  20. return unescape(arr[2]);
  21. else
  22. return null;
  23. },

4)Cookie的缺点:

  • Cookie需要在客户端和服务器端之间来回传送,会浪费不必要的资源
  • Cookie的存储大小有限制,对于每个域,一般只能设置20个cookie,每个cookie大小不能超过4KB
  • Cookie的安全性,cookie因为保存在客户端中,其中包含的任何数据都可以被他人访问,cookie安全性比较低

6.localStorage

是一种持久化的存储方式,如果不手动清除,数据永远不会过期。它也是采用Key - Value的方式存储数据,按域名将数据分别保存到对应数据库文件里。

  • 保存的数据长期存在,下一次访问该网站的时候,网页可以直接读取以前保存的数据。
  • 大小为5M左右。
  • 仅在客户端使用,不和服务端进行通信。
  • 存储的信息在同一域中是共享的。
  1. 设置:localStorage.setItem'name': 'xs'
  2. 获取:localStorage.getItem('name')
  3. 删除:localStorage.removeItem('name');

7.sessionStorage

对象值存储会话数据,其生命周期会存储到浏览器关闭。(在该过程中刷新页面其数据不受影响),使用方法与localStorage一致。

8.sessionStorage和localStorage区别:

  • localStorage是永久存储,除非手动删除。sessionStorage当会话结束(当前页面关闭的时候,自动销毁)
  • localStorage只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据。

9.indexedDB

优点:

  • 存储数据理论上没有上线
  • 所有操作都是异步,比同步操作性能更高,尤其是数据量大的情况下
  • 原生支持存储js对象
  • 以数据库的形式储存数据,数据管理更规范

10.浏览器的缓存

浏览器的缓存是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览。
image.png这种size大小不为0的请求,就是没有使用缓存。size是memory cache 和 disk cache就表示,浏览器并没有向服务器发送请求,而是直接读取了本地的缓存资源文件。

11.浏览器的缓存类型

  • memory cache
  • disk cache

memory cache:内存缓存,即使我们不设置缓存,当前的内存空间比较充裕的话,一些资源还是会被缓存下来。但这种缓存是暂时的,一旦关闭了浏览器,这一部分用于缓存的内存空间就会被释放掉。
内存缓存虽然比较高效,但还是受限于计算机内存的大小,所以能让我们使用的内存并不多,这个时候就需要硬盘来存储大量的缓存。

disk cache:存储在硬盘中的缓存,时效比较长,它会根据HTTP Header中设置的字段类型,来判断资源是否需要重新请求

12.缓存过程

浏览器在第一次请求资源后,会获取到请求的结果以及缓存标识,接下来,浏览器会根据第一次请求返回的响应头来确定缓存处理的方式,分别是强缓存和协商缓存
618215449-5c1b2856bf9d7_articlex.png

  1. 浏览器会先获取该资源缓存的header信息,根据其中的expires和cache-control判断是否命中强缓存,若命中则直接从缓存中获取资源,包括缓存的header信息,本次请求不会与服务器进行通信;
  2. 如果没有命中强缓存,浏览器会发送请求到服务器,该请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/IF-Modified-Since、Etag/IF-None-Match),由服务器根据请求中的相关header信息来对比结果是否命中协商缓存,若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容

13.强缓存

强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间
如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。

  • no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
  • no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
  • public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
  • private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。

14.协商缓存

协商缓存就是由服务器来确定缓存资源是否可用,客户端与服务器端通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。

服务器第一次返回资源时,会返回Last-Modified属性,表示改资源最后被更改的时间;浏览器第二次请求该资源时,会向服务端发送If-Modified-Since属性,询问该时间之后资源文件是否被修改过。

或者服务器第一次返回资源时,会返回Etag(资源文件的唯一标识,只要资源有变化,Etag就会重新生成),浏览器二次请求时会返回If-None-Match,服务端根据接收到的If-None-Match和之前的Etag进行对比,判断资源是否进行过修改,如果修改,则返回新的资源,否则命中协商缓存,返回304状态,从缓存中获取资源。

思考:为什么有了Last-Modified还需要Etag进行判断?
image.png
如图可以看出,Last-Modified返回的最小时间单位是秒,所以,服务器的资源和本地的资源有可能存在不一致,如果请求的时机正好在资源变动的1s之内,ETag使用的是唯一标识,能够很好的解决这个问题。

15.缓存方式总结

缓存类型 获取资源形式 状态码 发送请求到服务器
强缓存 从缓存取 200(from cache) 否,直接从缓存取
协商缓存 从缓存取 304(Not Modified) 是,通过服务器来告知缓存是否可用
  • html文件千万不能设置强缓存,目前前端开发页面,大多数情况下都是单页面应用,一旦有变动及时更新成功,所以html应该设置cache-control为no-cache。
  • CSS、JS、图片等资源,可以设置一个长时间的强缓存。在资源名(或者路径)中添加 hash, 版本号等动态字符,这样在更改资源的时候,可以通过更改这些动态字符来通知浏览器直接去请求新的资源,在文件不变动的情况下,直接使用本地缓存,不去向浏览器请求。

    16.浏览器清除缓存

    1)html中加上
    1. //不缓存
    2. <META HTTP-EQUIV="pragma" CONTENT="no-cache">
    3. <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
    4. <META HTTP-EQUIV="expires" CONTENT="0">
    2)页面中引用js的地方加上随机数
    1. URL 参数后加上 "?ran=" + Math.random(); //当然这里参数 ran可以任意取了
    2. URL 参数后加上 "?timestamp=" + new Date().getTime();
    3)强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache,服务器直接返回 200 和最新内容。

4)禁止强制缓存
image.png
5)nginx清除缓存
在nginx.conf加入如下规则:

  1. server {
  2. location ~* \.(html)$ {
  3. access_log off;
  4. add_header Cache-Control max-age=no-cache;
  5. }
  6. location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$ {
  7. # 同上,通配所有以.css/.js/...结尾的请求
  8. access_log off;
  9. add_header Cache-Control max-age=360000;
  10. }
  11. }

access_log off; 的含义是 关闭日志功能。

17.参考文献

https://zhuanlan.zhihu.com/p/93357692
https://www.jianshu.com/p/54cc04190252
https://www.cnblogs.com/tugenhua0707/p/10841267.html