HTTP 知识汇总

148 阅读20分钟

无论是对于面试,还是日常的开发,我们都会无时无刻接触到 HTTP 方面的相关知识,最近打算整理一波关于 HTTP 相关的知识,如有错误🙅,请大家指出。

题目一:URI 是什么?

URI(Universal Resource Identifier)统一资源标志符,它能在某一规则下将某一个资源唯一标记出来。比如一个人的身份证在现实生活中是唯一的,那它就是 URI 的实例,因为可以通过身份证指定标记这个人是谁。

在开发的过程中,我们听说过 URL(Universal Resource Locator)统一资源定位符。这两者之前有什么区别呢?

大家可以看一下 URL 的构成内容:

通过这种图我们大体了解 URL 的组成包含了哪些内容,具体就不细讲他们之前的含义了。由于 URL 可通过上面途中这些内容可以访问到一个唯一的站点,从概念上将它是 URI 的一个子集。

题目二:HTTP 状态码

客户端的请求发送给相应的服务器,都会得到服务器返回的一个包含 HTTP 状态码的请求头。这些请求头会告诉我们请求的状态,方面我们针对性的进行处理。

了解 HTTP 状态码有哪些分类

  • 1xx
    服务端收到请求,然后需要客户端继续执行请求操作。
  • 2xx
    服务端接收到请求,并且服务端正常返回请求内容给客户端。
  • 3xx
    资源重定向。
  • 4xx
    指客户端请求内容有误。
  • 5xx
    指服务端存在问题。

常见的 HTTP 状态码有哪些?它们相关的含义是什么?

  • 100: 表示服务端接收到请求的部分内容,客户端应继续发送其请求。
  • 101: 表示服务器接收到客户端的切换协议请求,服务器同意切换协议。需要注意的是协议只能从低版本往高版本协议进行切换。如 http 切换到 websocket
  • 200: 表示客户端正常请求到服务端,服务端成功返回响应给客户端。
  • 204: 含义与200相同,唯一不同的是没有响应内容。
  • 206: 表示服务端处理请求的部分内容。常用于 HTTP 分块下载资源断点续传
  • 300: 表示服务器返回多种资源特征和地址列表供用户选择。
  • 301: 表示资源被永久的替换了。之后相应的 URL 请求会自动从新的地址上获取。需要注意的是,被永久替换的地址会被浏览器缓存起来。
  • 302: 表示资源被临时改变。由于当前情况不会将改变后的 URL 缓存起来,所以每次请求依然会先调用老的地址,这也是跟 301 不一样的地方。
  • 304: 表示资源未被修改,当前情况服务器不会返回资源,而是会触发协商缓存,从缓存中直接获取。
  • 305: 表示所有请求被代理完成
  • 307: 临时重定向,跟 302 的区别在于,它只支持 GET 请求。
  • 400: 表示请求发出的语法存在问题。
  • 401: 表示需要进行用户身份验证。
  • 403: 表示服务端成功接收到客户端的请求,但是拒绝执行。
  • 404: 表示资源找不到。
  • 405: 表示当前请求的方法不被支持。
  • 408: 表示服务端等待客户端的请求过长,超时了。
  • 500: 表示服务端语法有误,导致请求异常。
  • 502: 表示网关或者代理服务器存在问题。
  • 503: 表示被请求的服务器暂时无法使用,可能在维护或者正在更新发布。
  • 504: 表示服务端为及时响应,请求超时。

看到上面的请求状态码是不是很多,估计头会稍微大一点😊,请不要担心,可以先尝试大体看一遍,然后结合实际工作中遇到的,再二次看会容易记住。

题目三:GET 和 POST 的区别

这一个问题其实我在之前写过了,但为了方便再在这边写一下。

首先,我们需要了解 GET 和 POST 是什么。当然,大家应该都知道的。但我还是想多说一下。GET 和 POST 都属于 HTTP 的请求方法。只是设计出来的用途不一样。

  • GET 方法用于获取资源,用于拿取操作。
  • POST 方法用于提交数据,用于提交指定资源

那它们的区别有哪些呢?下面会详细的列出。

  • 我们需要了解,冥等性非冥等性冥等性 指对资源无害,不会操作资源的。反之就是 非冥等性。GET 方法作为仅仅获取资源,不会对资源进行操作,所以它是冥等的。而 POST 会往服务器推送数据,所以它是非冥等的。
  • GET 请求存在安全问题,GET 请求的参数会被按照&的方式拼接在 URL 链接上。它的内容是可见的,敏感信息如果被携带上去,会被相关不法分子获取,进行非法操作。而 POST 请求它的请求参数会被放置在请求Body中。
  • 针对于安全问题,还有一点需要提及的是 GET 请求的参数由于被携带在 URL 上,所以参数只能按照 URL 编码方式进行加密处理,而 POST 请求的参数没有编码格式限制。
  • GET 请求的参数大小存在限制。URL 长度是存在限制的,链接最大只能到达 4kb,所以 GET 请求不能携带过多的参数。而 POST 的请求参数大小数量没有限制。
  • GET 请求会可以存在书签中,但是 POST 请求是不可以的。
  • GET 请求的参数可以被完整的保留下来,而 POST 是不可以的。
  • GET 请求参数只能接受 ASCLL 字符,其他字符会被转化为十六进制,而 POST 没有限制。
  • GET 请求可以被浏览器主动缓存,而 POST 方法是不可以的,只能通过设置。
  • GET 浏览器回退是无害的,但是 POST 回退就会再次发送提交操作。

题目四:网页加载的过程

一个网页的加载过程,很多面试官们都会去询问,毕竟你是前端开发者,如果连这个过程的细节都不知道,那你可能就不是一个合格的前端开发者了。下面是我自己根据自己的理解和相关材料总结的,如有不对的,请指出🙏。

首先,我们需要知道的是当网页访问的之前,肯定有一个契机。这个契机可能是你在浏览器上,输入了网址或者通过 a 标签访问等等。

然后,我们会去浏览器上访问相应的地址,比如访问 https://www.ghost.com 这个地址,当浏览器拿到这个地址之后,会先去本地 HOST 文件中查询有没有相应的 IP,如果有则从 HOST 取。如果没有则向更高层的 DNS 服务中获取。总之,网址存在,就会找到相应的 IP 的。需要注意的是如果 DNS 缓存中存在了这个 IP 就会取缓存中的,缓存中没有,就执行 DNS 查询,查询到 IP 地址。

拿到 IP 之后,客户端和服务端会建立 TCP 连接,然后进行 TCP/IP 三次握手。三次握手流程如下:

  • 客户端发送携带 SYN 的信息给服务端。
  • 服务端接收到客户端的携带的 SYN 信息后,要告诉客户端“我接收到了,没问题!”,所以会发送一个携带 SYN-ACK 的信息给客户端。
  • 客户端接受到服务端发送的携带 SYN-ACK 的信息之后,也需要告诉服务端"我这边也能接受到你给我的数据了,我们可以正式进行资源互通了",所以会发送一个包含 ACK 的信息给服务端。

如果网站是 HTTPS 的网站,则要比 HTTP 的网站多一步:TSL 握手。握手流程如下:

  • 客户端发送客户端问候消息,包含协议版本、客户端随机数和密码套件列表。
  • 服务端接收到客户端随机数以及客户端的参数和密码套件。因此服务端可以创建主密钥。
  • 服务器的问候包含服务器证书、数字签名、服务器随机数和公钥给客户端。
  • 最后客户端验证签名和证书,通过生成随机数,通过服务端给的公钥进行加密,返回给服务端。
  • 服务端接收到加密的数据之后,进行私钥解密,然后结束。

其次,浏览器发送 HTTP 请求拿去网站 HTML 代码。

随后,服务端响应请求,返回相应的 HTML 文件,浏览器拿到 HTML 代码。

再随后,浏览器解析 HTML 代码,获取相应所需要的资源(如js、css 等)

最后,浏览器引擎渲染页面呈现给用户。

🎉 上面就是所有的浏览器访问的流程了。

题目五:缓存

讲到缓存,在前端这边可以分为浏览器缓存HTTP 缓存两种

浏览器缓存下面分 Service Worker CacheMemory CacheDisk CachePush Cache
HTTP 缓存下面又分强缓存协商缓存

下面不会讲的很仔细,但是每个点会大致的过一遍,如果有人想看更细的缓存知识,可以查阅其它文章。

浏览器缓存

Service Worker Cache

Service Worker Cache 的出现是为了处理离线应用。它可以很容易地指定需要离线缓存的资源。浏览器可以在这边进行查看。 Service Worker Cache 有别于其它缓存机制,我们可以自由的控制缓存、文件匹配、读取缓存、并且是持续性的。当没有命中规则的时候才会去请求数据。

可以访问 Service Worker API 官网[1] 进行查阅更多内容。

Memory Cache

Memory Cache 看意思就明白缓存数据存放在浏览器内存中,读取内存的数据是快速和高效的。但是放在内存的数据过多,就会导致浏览器占据计算机内存过多,也会影响计算机运行性能。还有一个缺陷是浏览器或者 Tab 关闭,内存就会被释放。

Disk Cache

Disk Cache 将数据存放在硬盘中,读取速度仅次于 Memory Cache,但是可以长期存储,可以自定义失效时间,覆盖面比较大。Disk Cache 会根据 HTTP Header 来启动缓存策略做缓存。

Push Cache

当以上三种缓存都没有命中时才会使用Push Cache。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂。

HTTP 缓存

Http 请求第一次的流程图如下: 由图可知:

  • 每次发送 Http 请求都会从浏览器缓存中获取缓存结果和缓存标记,无论有没有。
  • 每次拿到数据,都会将请求结果写入到浏览器缓存中,同时也会将缓存标记写入。

强缓存

强缓存就是每次都会去浏览器获取缓存结果,然后根据缓存结果的有效性来决定是否使用缓存结果。

存在以下三种情况:

  • 浏览器向浏览器缓存获取缓存结果和缓存标记,发现没有,则直接向服务器获取。
  • 浏览器向浏览器缓存获取缓存结果和缓存标记,发现缓存结果和缓存标记已经失效,则直接向服务器获取。
  • 浏览器向浏览器缓存获取缓存结果和缓存标记,发现缓存结果和缓存标记存在,则直接使用缓存结果,而不会向服务器请求。

通常问这方面问题的话都会去问请求头中涉及的两个字段 ExpiresCache-Control。下面解释一下这两个字段。

Expires

Expires 属于 HTTP/1.0 所定义的字段。然后,它的值表示请求过期时间,如果当前客户端时间比它的小,则使用缓存数据。反之,不使用。当然,在 HTTP/1.1 中,当前字段已经被替换掉了。由于客户端如果和服务端的时间有误差,就会因缓存结果有误出现问题。

Cache-Control

Cache-Control 用于 HTTP/1.1 用于控制网页缓存。当 Expires 和 Cache-Control 同时存在的时候,会使用 Cache-Control。它允许设置的值如下:

public:所有内容都将被缓存(客户端和代理服务器都可缓存)
private:所有内容只有客户端可以缓存,Cache-Control 的默认取值
no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。

协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。

协商缓存结果有两种情况。

  • 第一种,命中🎯缓存,返回 304 状态码
  • 第二种,没有命中🎯缓存,从服务器正常请求资源

控制协商缓存的字段有下面几种:

  • Last-Modified / If-Modified-Since
  • Etag / If-None-Match

备注:Etag / If-None-Match 的优先级比 Last-Modified / If-Modified-Since 高。

下面解释一下上面两个请求头的含义:

Last-Modified / If-Modified-Since

Last-Modified 表示服务器响应请求时,返回该资源在服务器最后被修改的时间。

If-Modified-Since 表示上一次请求返回的 Last-Modified 的值,通过这个值告诉服务器该资源上次请求返回的最后修改时间。当服务器发现请求中存在 If-Modified-Since,则会将它的值跟现在服务器上的值进行对比,如果发现服务器最后修改时间大于这个值,则返回新的资源,从缓存中获取。反之,则返回 304,可继续从缓存中获取。

Etag / If-None-Match

Etag 表示服务器响应请求时,返回当前资源的唯一标识(服务器自己生成的)。

If-None-Match 表示客户端再给服务器发送请求的时候,这个值指的是上一次请求返回的 Etag。当服务器发现请求中存在 If-None-Match,则会将它的值跟现在服务器上的值进行对比,如果一样则返回 304,可继续从缓存中获取。如果不一样,则返回新的资源。

题目六:HTTP 和 HTTPS

我们无时无刻都在跟网络打关系,所以经常看到网页上要么是 http://www.ghost.com,要么是 https://www.ghost.com。所以,这个 httphttps 有啥区别呢?它们个自己优缺点又是什么呢?可以阅读下面这一模块的内容。

HTTP 的特点和缺点

特点:无连接无状态灵活简单快速

  • 无连接:每次请求都要连接一次,请求结束就会断掉,不会保持连接。
  • 无状态:每次请求都是独立的,请求结束不会记录连接的任何信息,减少网络开销。
  • 灵活:通过 HTTP 协议中头部 Content-Type 标记,可以传输任何数据类型的数据对象(文本、图片、视频等),非常的灵活。
  • 快速简单:发送请求访问某个资源时,只需传送请求方法和 URL 即可,使用简单,正由于 HTTP 协议简单,是的 HTTP 服务器的程序规模小,因而通信速度很快。

缺点:无状态不安全明文传输队头阻塞

  • 无状态:请求不会记录任何连接信息,没有记忆,就无法区分多次请求者是否是一个客户端发出的,意味者后续身份信息都需要重新传递,这样可能导致不必要的信息传递,导致传送数据量增大。
  • 不安全:明文传输能被窃听篡改,导致数据不安全。
  • 明文传输:报文使用的以明文的方式传递的。
  • 队头阻塞:开启长连接时,只建立一个 TCP 连接,同一时刻只能处理一个请求,那么一个请求耗时过长,就会导致其他请求被阻塞到。

HTTPS 的特点和缺点

特点:内容加密身份认证数据完整性

  • 内容加密:请求的内容会被加密,中间内容无法查看原始内容。
  • 身份认证:保证用户访问正确。如果站点被劫持,也会提醒用户当前站点被劫持,警告用户。
  • 数据完整性:数据完整,防止内容被第三方冒充或者篡改

缺点:需要花钱证书需要绑定 IP耗费服务器资源会增多耗时

  • 需要花钱:需要花钱买证书,功能越强大的证书,需要花费的费用会越贵。
  • 证书需要绑定 IP:不能再同一个 IP 上绑定多个域名。
  • 耗费服务器资源会增多:HTTPS 双方加解密,耗费更多的服务器资源。
  • 耗时:中间增加了 TLS/SSL握手,一定程度上降低可用户访问的速度。

备注:整体上 HTTPS 不是绝对的安全,但是这是相对来说最安全的解决方案了,大大减少了被攻击的几率。

HTTP 和 HTTPS 有什么不同?

  • HTTP 是明文传输的,不安全,HTTPS 是加密传输的,安全的多。
  • HTTP 标准端口是 80,HTTPS 标准端口是 443
  • HTTP 不用认证证书 免费,HTTPS 需要购买证书进行认证。
  • 连接方式不同, HTTP 只需要进行三次握手,但是 HTTPS 需要进行更多
  • HTTP 在 OSI 网络模型中是 应用层,而 HTTPS 的 TLS 是在传输层
  • HTTP 是无状态的,而 HTTPS 是有状态的。

题目七:跨域

在学习跨域之前,我们需要了解为什么会出现跨域?什么是跨域?然后,下面也会告诉大家如何解决跨域问题。

为什么会出现跨域?什么是跨域?

跨域是浏览器为了保护网站资源的一种手段。浏览器规定的同源策略的限制如下,不满足同源策略都会被限制。

  • 不同站点之间不能互相访问彼此的 Cookie、localStorage、IndexedDB 等存储性内容
  • 不同站点之间不能操作彼此的 DOM 节点。
  • 不同站点之间彼此发送 AJAX 请求会被浏览器拦截。

但是有以下几个标签,不会受同源策略的限制

  • <img src=xxx />
  • <link href=xxx />
  • <script src=xxx>

什么是跨域?就是当两个或多个站点的 协议主机端口号 不一样时,它们彼此访问,就会出现跨域。

怎么解决跨域问题?

1. JSONP

利用 script 标签没有跨域限制的特点,网页可以得到从其他来源动态产生的 JSON 数据。JSONP 请求一定需要服务端做支持才可以。实现的核心是 回调函数

前端实现代码:

// index.html
function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script')
    window[callback] = function(data) {
      resolve(data)
      document.body.removeChild(script)
    }
    params = { ...params, callback } // wd=b&callback=show
    let arrs = []
    for (let key in params) {
      arrs.push(`${key}=${params[key]}`)
    }
    script.src = `${url}?${arrs.join('&')}`
    document.body.appendChild(script)
  })
}
jsonp({
  url'http://localhost:3000/say',
  params: { wd'Iloveyou' },
  callback'show'
}).then(data => {
  console.log(data)
})

后端实现代码:

// server.js
let express = require('express')
let app = express()
app.get('/say'function(req, res) {
  let { wd, callback } = req.query
  console.log(wd) // Iloveyou
  console.log(callback) // show
  res.end(`${callback}('T hate you, javascript')`)
})
app.listen(3000)

2. CORS

CORS 需要浏览器和后端同时支持。实现 CORS 的关键是在后端。服务端需要设置 Access-Control-Allow-Origin 就可以开启 CORS 了。如果设置了只有哪些站点可以访问,那么只有这些站点访问当前接口不会出现跨域,其他的站点都会出现。如果设置为 Access-Control-Allow-Origin: *,则所有的站点访问当前接口都不会出现跨域。

这里只大体列一下核心,想要了解更多可自行到网上去查找。毕竟一个知识内容实在挺多的😢。或者关注我,等我后期梳理完这次要梳理的知识再一一做讲解😄。

3. postmessage

postmessage 方法允许来自不同同源脚本采用异步方式进行有限的通信,可以实现跨文本、多窗口、跨域消息传递。

语法: otherWindow.postMessage(message, targetOrigin, [transfer]);

  • message:将要发送到其他 window的数据。
  • targetOrigin:通过窗口的 origin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个 URI。
  • transfer:是一串和 message 同时传递的 Transferable 对象。

代码示例

前端实现代码:

/*
 * A 窗口的域名是<http://example.com:8080>,以下是 A 窗口的 script 标签下的代码:
 */

var popup = window.open(...popup details...);

// 如果弹出框没有被阻止且加载完成

// 这行语句没有发送信息出去,即使假设当前页面没有改变 location(因为 targetOrigin 设置不对)
popup.postMessage("The user is 'bob' and the password is 'secret'",
                  "https://secure.example.net");

// 假设当前页面没有改变 location,这条语句会成功添加 message 到发送队列中去(targetOrigin 设置对了)
popup.postMessage("hello there!""http://example.org");

function receiveMessage(event)
{
  // 我们能相信信息的发送者吗?(也许这个发送者和我们最初打开的不是同一个页面).
  if (event.origin !== "http://example.org")
    return;

  // event.source 是我们通过 window.open 打开的弹出页面 popup
  // event.data 是 popup 发送给当前页面的消息 "hi there yourself!  the secret response is: rheeeeet!"
}
window.addEventListener("message", receiveMessage, false);
/*
 * 弹出页 popup 域名是<http://example.org>,以下是 script 标签中的代码:
 */

//当 A 页面 postMessage 被调用后,这个 function 被 addEventListener 调用
function receiveMessage(event)
{
  // 我们能信任信息来源吗?
  if (event.origin !== "http://example.com:8080")
    return;

  // event.source 就当前弹出页的来源页面
  // event.data 是 "hello there!"

  // 假设你已经验证了所受到信息的 origin (任何时候你都应该这样做), 一个很方便的方式就是把 event.source
  // 作为回信的对象,并且把 event.origin 作为 targetOrigin
  event.source.postMessage("hi there yourself!  the secret response " +
                           "is: rheeeeet!",
                           event.origin);
}

window.addEventListener("message", receiveMessage, false);

更多内容请查阅 MDN postmessage 官网文档[2]。

4. Websocket

Websocket 是 HTML5 的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket 和 HTTP 都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。

代码示例

前端实现代码:

// socket.html
<script>
let socket = new WebSocket('ws://localhost:3000');

socket.onopen = function () {
  socket.send('Hello,javascript');//向服务器发送数据
}

socket.onmessage = function (e) {
  console.log(e.data);//接收服务器返回的数据
}
</script>

服务端实现代码:

// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');

let wss = new WebSocket.Server({ port3000 });

wss.on('connection',function(ws) {
  ws.on('message'function (data) {
    console.log(data);
    ws.send('T hate you, javascript')
  });
})

5. nginx 反向代理

通过 nginx 配置一个代理服务器(域名与客户端相同,端口不同)做跳板机,反向代理访问服务端接口,并且可以顺便修改 cookie 中 domain 信息,方便当前域 cookie 写入,实现跨域登录。

nginx 配置如下:

// proxy服务器
server {
    listen       81;
    server_name  www.ghost.com;
    location / {
        proxy_pass   http://www.xxxx.com:8080;  #反向代理
        proxy_cookie_domain www.xxxx.com www.ghost.com; #修改 cookie 里域名
        index  index.html index.htm;

        # 当用 webpack-dev-server 等中间件代理接口访问 nignx 时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.ghost.com;  #当前端只跨域不带 cookie 时,可为 *
        add_header Access-Control-Allow-Credentials true;
    }
}

6. window.name + iframe

通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的 window.name 从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

代码示例: a.html(b.html 和 a.html 同源)

// a.html(http://localhost:3000/b.html)
<iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
<script>
  let first = true
  // onload事件会触发2次,第1次加载跨域页,并留存数据于 window.name
  function load() {
    if(first){
    // 第1次 onload (跨域页)成功后,切换到同域代理页面
      let iframe = document.getElementById('iframe');
      iframe.src = 'http://localhost:3000/b.html';
      first = false;
    } else {
    // 第2次onload(同域 b.html 页)成功后,读取同域 window.name中数据
      console.log(iframe.contentWindow.name);
    }
  }
</script>

c.html (c.html 和 a.html 不同源)

// c.html(http://localhost:4000/c.html)
<script>
  window.name = 'T hate you, javascript'  
</script>

题目八:如何处理大文件传输

  • 开启 gzip 进行数据压缩。请求头示例:content-encoding: gzip
  • 通过分块传输编码,设置 Transfer-Encoding: chunkedTransfer-Encoding: gzip, chunked
  • 流式传输(需要了解的可关注后期仔细讲解)。

题目九:Cookie、sessionStorage 和 localstorage

共同点:

  • 都保存在浏览器端,且是同源的。

不同点:

  • cookie 数据始终在同源的 http 请求中携带,而 sessionStorage 和 localstorage 不会再请求中携带,仅仅在本地存储
  • 存储大小区别,cookie 是4k,sessionStorage 和 localstorage 可以达到5M甚至更大。
  • 数据有效时间区别: sessionStorage 仅仅是会话级别的存储,它只在当前浏览器关闭前有效,不能持久保持;localStorage 始终有效,即使窗口或浏览器关闭也一直有效,除非用户手动删除,其才会失效;cookie 只在设置的 cookie 过期时间之前一直有效。
  • 作用域区别:sessionStorage 不在不同的浏览器窗口中共享,即使是同一个页面; localStorage 和 cookie 在所有同源窗口是共享的。
  • sessionStorage 和 localstorage 支持事件通知机制,可以将数据更新的通知发送给监听者。sessionStorage 和 localstorage 的 api 接口使用更方便。

题目十:如何解决 HTTP 的队头阻塞问题

什么是队头阻塞

引用知乎 Xiaojian Hong[3] 的话:当单个(慢)对象阻止其他/后续的对象前进时。

更简单的讲解HTTP灵魂之问,巩固你的 HTTP 知识体系 :从前面的小节可以知道,HTTP 传输是基于请求-应答的模式进行的,报文必须是一发一收,但值得注意的是,里面的任务被放在一个任务队列中串行执行,一旦队首的请求处理太慢,就会阻塞后面请求的处理。这就是著名的HTTP队头阻塞问题。

解决方案

并发连接

对于一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其它所有任务。在 RFC2616 规定过客户端最多并发 2 个连接,不过事实上在现在的浏览器标准中,这个上限要多很多,Chrome 中是 6 个。

但其实,即使是提高了并发连接,还是不能满足人们对性能的需求。

域名分片

一个域名不是可以并发 6 个长连接吗?那我就多分几个域名。 比如 a.ghost.com 、b.ghost.com。

这样一个 ghost.com 域名下可以分出非常多的二级域名,而它们都指向同样的一台服务器,能够并发的长连接数更多了,事实上也更好地解决了队头阻塞的问题。

细节上请参考:关于队头阻塞(Head-of-Line blocking),看这一篇就足够了[4]

参考资料

[1]

Service Worker API 官网: developer.mozilla.org/zh-CN/docs/…

[2]

MDN postmessage 官网文档: developer.mozilla.org/zh-CN/docs/…

[3]

Xiaojian Hong: zhuanlan.zhihu.com/p/330300133

[4]

关于队头阻塞(Head-of-Line blocking),看这一篇就足够了: zhuanlan.zhihu.com/p/330300133