likes
comments
collection
share

前端面试基础 - 浏览器与网络篇

作者站长头像
站长
· 阅读数 1

前端基础 - 浏览器篇

浏览器缓存

相关问题引申: 性能优化 , 输入一个url到页面渲染的全过程 (这些超链接以后补充)

关于浏览器的缓存其实我们可以把他拆解为三个角度去解释, 什么是浏览器缓存, 缓存发生在什么阶段, 有什么作用. 浏览器的缓存机制其实就是我们常说的HTTP缓存机制

引用MDN上的话来解释这是什么: HTTP缓存会与存储与请求关联的响应, 并将存储的响应复用于后续请求

那么我们使用缓存会有什么好处: 当响应可复用时, 服务器就不需要处理请求, 这样可以减轻服务器的负载, 并且客户端通过缓存获取资源, 相比于将请求传递到服务器再返回, 速度上也会有一个提升.

针对于缓存我们可以把它从概念上分为两种: 强缓存协商缓存

强缓存

概念

当客户端第一次访问页面时, 服务器会将该资源的缓存规则存入HTTP Response Header中和请求结果一起返回给浏览器, 控制强缓存的字段为ExpiresCache-Control.

那么浏览器会在js和图片文件解析执行后直接存入内存缓存中, css文件存入硬盘文件中, 这边有提到两个点分别是内存缓存(memory cache)和硬盘缓存(disk cache)

这两者有什么区别呢

  • memory cache : 内存缓存会有快速读取(会将编译后的文件直接存入进程中的内存中, 方便下次运行时快速读取)和时效性(当tab页关闭后, 数据就不存在了)两个特性 , 在关闭tab后, 下次的读取会变成从disk cache读取
  • disk cacha: 关闭tab或者关闭浏览器后, 数据依然存在, 但由于需要进行I/O操作重新解析内容, 所以速度相对会比较慢

根据以上的概念我们可以得知浏览器会优先读取memory cache中的缓存

用法

控制强缓存的字段

Expires

是HTTP 1.0控制网页缓存的字段, 值为服务器返回该请求结果的到期时间, 再次发起请求的客户端时间小于Expires值时, 可以直接使用缓存结果. 在HTTP的升级中, 该属性已经被Cache-Control替代, 由于这边判断缓存使用的是客户端时间, 所以会有时间不准确问题导致的缓存失效等问题. 如果该属性和Cache-Control同时存在, 那么只有Cache-Control生效.

Expires: Tue, 28 Feb 2022 22:22:22 GMT
Cache-Control

在讲到Cache-Control之前, 我们可能需要明确几个概念

  • 私有缓存 : 绑定到客户端的缓存, 通常是浏览器缓存. 存储的响应不与其他客户端共享, 可以存储用户的个性化响应.
  • 共享缓存: 位于客户端与服务器之间, 可以存储在用户之间共享的响应, 就比如公司架设的内部Web代理

了解以上概念后我们可以去看Cache-Control的几个属性

所有内容都会被缓存(客户端和代理服务器都可以缓存)
Cache-Control: public

只有客户端可以缓存, Cache-control的默认取值
Cache-Control: private

基于age的缓存策略, 存储的HTTP响应有两种状态, fresh(有效)和stale(已过期)
确定两者状态的是age: 代表响应生成以来经过的时间
Cache-Control: max-age=604800


强制重新验证, 如果不希望重复使用响应, 始终从服务器获取最新内容, 跳过之后还会有协商缓存进行验证
Cache-Control: no-cache

如果不希望将相应储存在任何缓存中, 即不适用强缓存和不适用协商缓存
Cache-Control: no-store


协商缓存

在强缓存失效后, 浏览器携带缓存标识向服务器发起请求, 服务器根据缓存标识局决定是否使用缓存, 与强缓存同理, 协商缓存的标识也是在HTTP请求头中一起返回到浏览器的

Last-Modified / If-Modified-Since

服务器响应请求时, 包含源头服务器认定资源做出修改的日期, 精确度比ETag要低, 是一个备用机制, 包含 If-Modified-SinceIf-Unmodified-Since首部条件的请求会使用这个字段 If-Modified-Since : 客户端再次发起请求时, 携带上次请求返回的Last-Modified值, 服务器会与该资源在服务器最后修改的时间进行对比, 重新返回资源状态码为200, 返回304为无更新, 可以使用缓存文件

Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT

Etag

服务器响应请求时, 返回给当前资源文件的一个唯一标识

If-None-Match: 客户端再次发起请求时, 携带上次请求返回的Etag值, 服务器收到请求后会与服务器端存储的ETag值进行对比, 一直返回304告知无需更新, 不一致返回200和资源文件

一些引申与思考

引申问题1: 怎么去删除存储的响应

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Cache-Control: max-age=31536000

<!doctype html>

当我们服务器上的资源过期后, 比如我们这边想要去清除这个强缓存

方法1: 通过POST等方法重新请求资源

但假设这是一个C端用户在使用, 并且因为强缓存的原因没有请求到达服务器, 用户也无法通过POST方法去发送请求, 那么也就是说除了用户自己手动强制清除缓存, 很难做出清除max-age缓存过大长的操作

方法2: 缓存破坏

最适合缓存的是静态不可变文件, 但对于会变化的资源, 通常最佳实践是每次变化时改变URL, 就比如一些经常变化的js和css文件, 我们可以使用基于版本号或者哈希值修改部分url来提供, 缓存会根据他们的url来区分资源, 如果更新资源时url发生变化, 缓存将不会被重用

缓存破坏只使用于一些子资源, 例如主题html中引入的js资源

所以虽然缓存减少了对服务器的访问, 但也意味着服务器失去了对该url的控制, 在资源频繁更新的情况下, 我们还是需要评估使用no-cache以便服务器返回预期的响应

引申问题2:常用缓存头

QPACK是压缩HTTP标准字段的标准, 提供了一些常用缓存头的值表, 如果选择了其中的一些标号, 在HTTP3传输时将值压缩为一个字节

36 cache-control max-age=0
37 cache-control max-age=604800
38 cache-control max-age=2592000
39 cache-control no-cache
40 cache-control no-store
41 cache-control public, max-age=31536000

面试中的回答: 说出浏览器的缓存机制, HTTP缓存分为强缓存和协商缓存, 两种缓存发生的时机和优先级, 常用的属性和配置, 缓存破坏, 通过常用缓存头引出HTTP3

developer.mozilla.org/zh-CN/docs/…


Cookie, LocalStorage, SessionStorage

当网页刷新的时候, 很多数据都会被清空, 如果说我们要对数据进行一个存储, 就需要用到本地储存技术, 这边将本地储存技术分为三种, 我们先对于cookie做一个详细了解

Cookie

是一个HTTP请求标头, 通过服务器Set-cookie投放或者js的Document.cookie方法设置, 然后存储到客户端的HTTP cookie. 它用于告知服务端两个请求是否来自于同一浏览器, 例如保持用户的登录状态. 他的主要作用就是为无状态的HTTP协议提供记录稳定状态的能力

那么为什么我们要把他和localStorage和sessionStorage对比, 从他的功能角度, 其实更适合和 session, token, JWT 放在一起对比. 在这里其实可以在MDN上看到, 在之前cookie被用于客户端数据存储, 因为当时没有合适的存储手段, 由于服务器指定cookie后, 浏览器每次请求都会携带cookie数据, 会带来额外的性能开销, 当有sessionStorage和localStorage后, cookie也就不被用来做客户端数据的存储

这边我们还可以引申出cookie的一些其他内容, 例如

  • cookie的生命周期, 通过expires, max-age等属性设置
  • 保证cookie被安全发送的方式, Secure属性(只能通过被HTTPS加密过的请求发送给服务端), HttpOnly属性(js的Document.cookie api无法方位带HttpOnly属性的cookie, 这其实是对XSS攻击的一种防范方式)
  • 第三方cookie: 这个也就是我们常见到的, 我们访问网站时提示的第三方站点手机cookie, 主要用于埋点追踪与广告之类的.

OK, 简单了解完cookie之后我们再对它的存储方面做一些总结, 方便与另外两个进行一个对比

  • 存储时间: 可以设置失效时间, 没有设置的话就在浏览器关闭后失效\
  • 存储大小: 4kb左右
  • 缺点: 每次发送请求会携带, 影响性能

localStorage & sessionStorage

两者都是用于Web本地存储的场景, 使用上也是通过调用对应的API, 比如getItem, setItem

两者的区别

  • 存储大小: 都是5MB左右
  • 存储位置: 保存在客户端
  • 生命周期:
    • localStorage: 除非手动清除, 不然永久有效
    • sessionStorage: 适合做临时的一次性数据, 开启多个Tab时, 会常见自己的sessionStorage, 刷新等操作不会清除, 关闭浏览器窗口后清除