[计算机网络]——HTTP

254 阅读27分钟

Http

http报文

http报文结构具体如下:

起始行 + 头部 + 空行 + 实体

起始行

对于请求报文而言,起始行类似下面这样

GET /home HTTP/1.1

也就是方法 + 路径+ http版本

对于响应报文来说,起始行一般长这样

HTTP/1.1 200 OK

http版本 + 状态码 + 原因组成

头部

请求头和响应头中包含较多的字段,具体可查看:

kb.cnblogs.com/page/92320/

空行

很重要,用来区分开头部实体

如果在头部中间故意加一个空行,那么空行后面的内容都会被视作实体

实体

具体的数据,body部分。请求报文对应的是请求体,响应报文对应的是响应体

例子

请求

img

响应

img

请求方法

http/1.1规定了以下请求方法,注意都是大写

  • GET:通常用来获取资源

  • HEAD:获取资源的元信息

  • POST:提交数据,即上传数据

  • PUT:修改数据

  • DELETE:删除资源(几乎用不到)

  • CONNECT:建立连接隧道,用于代理服务器

  • OPTIONS:列出可对资源实行的请求方法,一般浏览器用于跨域前的预请求,判断是否可以与服务端通信

  • TRACE:追踪请求-响应的传输路径

GET和POST的区别

  1. TCP层面
  • GET产生一个TCP数据包,对于GET方式的请求,浏览器会把http的header和data一并发送出去,服务器响应200

  • POST产生两个TCP数据包,对于POST,浏览器会先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200

  • 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次

  1. HTTP规定
  • 语义不同,GET是获取数据,POST是提交数据

  • GET在浏览器回退是无害的,而POST是会再次提交数据

  • 缓存机制不同

    • GET请求会被浏览器主动cache,也就是主动缓存,而POST不会,除非手动设置
    • GET请求参数会被完整地保留在浏览器历史记录里面,而POST中的参数不会被保留
    • GET产生的URL地址可以被Bookmark,也就是进行书签收藏,有助于迅速查找,而POST不可以
  • 编码方式不同

    • GET请求只能进行URL编码(application/x-www-form-urlencoded)
    • POST支持多种编码方式(application/x-www-form-urlencoded或multipart/form-data)
  • GET参数通过URL传递,POST放在Request body中

  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制

  1. 浏览器层面
  • GET请求在URL中传送参数是有长度限制的,不同浏览器的限制大小不一样,而POST没有限制

URL和URI的区别

统一资源标识符URI就是在某一规则下能把一个资源独一无二地标识出来。

拿人做例子,一个人的身份证就是URI,因为通过身份证能让我们能且仅能缺点一个人。

统一资源定位符URL,比如说:

动物住址协议://地球/中国/浙江省/杭州市/西湖区/某大学/14号宿舍楼/525号寝/张三.人

这样的一个字符串同样也唯一确定了一个人,起到了URI的作用,所以URL是URI的子集

可以这样理解:URI不一定非得是通过号码去确定,URI是在某一规则下标识出一个资源的字符串,通过地址或者号码都是可行的规则,其中通过地址规则实现的URI就被称作URL,URL是URI的一种实现,就像三角形包含等边三角形一样

HTTP状态码

1xx

表示目前是协议处理的中间状态,还需要后续操作

  • 100

    • 表示目前为止一切正常,客户端应该继续请求,如果已完成请求则忽略
  • 101

    • 表示服务器应客户端升级协议的请求正在进行协议切换,如切换成websocket或http2.0

2xx

表示成功的状态

  • 200

    • 表示请求已经成功,默认情况下状态码为200的响应可以被缓存
  • 201

    • 表示请求已经被成功处理,并且创建了新的资源,新的资源在应答返回之前已经被创建
  • 204

    • 结果正确处理了,但是服务端没数据给客户端,即响应报文没有实体主体,一般用于服务器接受客户端消息,但不必回复内容的情况
    • 在PUT请求中进行资源更新,但不需要改变当前展示给用户的页面,那么返回204 No Content。如果创建了新资源,那么返回201 Created。如果页面需要更新以后的新资源,返回200 OK
  • 206

    • 206 Partial Content,表示部分内容,该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容。

3xx

重定向状态,资源位置发生变动,需要重新请求

  • 301&302

    • 301表示永久重定向,说明请求的资源已经被移动到了由Location头部指定的url上,是固定的不会再改变,搜索引擎会根据该响应修正;而302表示的是临时重定向。
    • 比如网站从HTTP升级到了HTTPS,以前的站点不再用了,应当返回301,这个时候浏览器会默认做缓存优化,第二次访问的时候会自动访问重定向的那个地址,而如果只是暂时不可用,那么返回302即可,和301不同的是浏览器并不会做缓存
  • 303

    • 效果和302一样。但是他明确规定了浏览器要用GET方法去访问新提供的URI
  • 304

    • 该状态码和重定向没有关系,而是走缓存路线,该状态码意味着命中了协商缓存
    • 说明所请求的资源在客户端本地未修改,服务器无需再次传输请求的内容,客户端可以直接使用缓存的内容
  • 307

    • 临时重定向,类似302,区别在于能够确保请求方法和消息主体不会发生改变
  • 308

    • 永久重定向,类似301,区别在于能够确保请求方法和消息主体不会发生改变

4xx

请求报文有误

  • 400

    • 开发者经常看到一头雾水,只是笼统地提示了一下错误,并不知道哪里出错了,一般是请求参数格式错误
  • 401

    • 请求需要认证的资源,但还没有认证,需要在请求主体加应该请求头:Authentic,实际情况中比如是忘记带token
  • 403

    • 实际上并不是请求报文出错,而是服务器禁止访问,一般是因为权限不够
  • 404

    • 表面服务器上没有这个资源
  • 405

    • 405 Method Not Allowed,表面服务器禁止了使用当前HTTP方法的请求,一般是请求方法错了
  • 406

    • 406 Not Acceptable,表示服务器不支持Accept、Accept-Charset、Accept-Encoding、 Accept-Language header 所要求的
  • 408

    • 408 Request Timeout服务器等待时间太长
  • 409

    • 请求发生了冲突
    • 冲突最有可能发生在对PUT请求的响应中,例如当上传文件的版本比服务器上已存在的要旧时,从而导致版本冲突,那么就可能收到409的响应
  • 410

    • 说明请求的内容在服务器上不存在,同时是永久性丢失,如果不清楚是否为永久性或临时性丢失,则应该使用404
  • 413

    • 表示请求主体的大小超过了服务器愿意或有能力处理的限度,服务器可能会关闭连接以防止客户端继续发送请求
    • 如果“超出限度”是暂时性的,服务器应该返回Retry-After首部字段,说明这是暂时性的,以及客户端可以在什么时间后重试
  • 414

    • URI过长,表示客户端所请求的URI超过了服务器允许的范围
  • 431

    • 由于请求中的首部字段的值太大,服务器拒绝接受客户端的请求

5xx

  • 500

    • 服务器内部发生错误,出了啥错我们也不知道
  • 501

    • 服务器不支持请求的功能,无法完成请求,表示method不被服务器支持,无法处理。这里要和405 Method Not Allowed区分,405是服务器本身支持这个请求方法,但是请求接口时却用了别的方法,例如应该用put却用了delete,就返回405
  • 502

    • 网关错误,服务器自身的正常的。
  • 503

    • 表示服务器尚未处于可以接受请求的状态,通常造成这种情况的原因是由于服务器停机维护或已超载。
  • 505

    • 服务器不支持请求的HTTP协议的版本

HTTP如何处理大文件的传输

对于几百M甚至上G的大文件来说,如果要一口气全部传输过来显示是不现实的,会有大量的等待时间,严重影响用户体验。HTTP针对这一场景采取了范围请求的解决方案,允许客户端仅请求一个资源的一部分。

如何支持

服务器要支持**范围请求,**要加上这样一个响应头

Accept-Ranges: none

Range字段

对于客户端而言,它需要指定请求哪一部分,通过Range这个请求头字段确定,格式为bytes=x-y。如0-499表示从开始到第499个字节。

服务器收到请求后,如果越界了,则返回416错误码,否则读取响应的片段,返回206状态码。

举例

// 单段数据
Range: bytes=0-9
// 多段数据
Range: bytes=0-9, 30-39

单段数据

单段数据的请求,返回的响应如下:

HTTP/1.1 206 Partial Content
Content-Length: 10
Accept-Ranges: bytes
Content-Range: bytes 0-9/100

i am xxxxx

0-9表示请求的返回,100表示资源的总大小

多段数据

HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=00000010101
Content-Length: 189
Connection: keep-alive
Accept-Ranges: bytes


--00000010101
Content-Type: text/plain
Content-Range: bytes 0-9/96

i am xxxxx
--00000010101
Content-Type: text/plain
Content-Range: bytes 30-39/96

eex jspy e
--00000010101--

使用boundary进行分割,最后的分隔符会添加--表示结束

什么是持久连接

http1.0协议采用的是“请求——应答”模式,当使用普通模式,每个请求/应答,客户都要与服务端建立一个连接,完成之后立即断开连接(http协议为无连接协议)

http1.1支持长连接,即请求头添加Connection:Keep-Alive,使用Keep-Alive模式建立一个TCP连接后使客户端到服务端的连接持续有效,可以发送多个请求,当出现对服务器的后续请求时,Keep-Alive功能能避免重新建立连接

img

长连接优缺点

优点

  • 减少CPU以及内存的使用,因为不需要经常建立和关闭连接

  • 支持管道化的请求以及响应模式

  • 减少网络堵塞,因为减少了TCP请求

  • 发生错误时,也可以在不关闭连接的情况下进行错误提示

缺点

  • 一个长连接建立后,如果一直保持连接,会浪费服务器的资源,可以在服务端配置keepalive_timeout设置长连接超时时间
  • 可能造成队头阻塞

什么是管道化

http1.1在使用长连接的情况下,建立一个连接通信后,连接上消息的传递类似于

请求1 -> 响应1 -> 请求2 -> 响应2

管道化连接的消息就变成了类似这样

请求1 -> 请求2 -> 响应1 -> 响应2

管道化是在同一个TCP连接里发一个请求后不必等其回来就可以继续发送请求出去,这样可以减少整体响应的时间,但是服务器还是会安装请求的顺序响应,如果有许多请求,而前面的请求响应比较慢,就会造成队头阻塞

HTTP1.1如何解决HTTP的队头阻塞问题

什么是队头阻塞

由于HTTP传输是基于请求-应答的模式进行的,报文必须是一发一收,但值得注意的是,里面的任务被放在了一个任务队列中串行执行,一旦队首的请求处理太慢,就会阻塞后面请求的处理,这就是著名的HTTP队头阻塞问题。

并发连接

对于一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其他所有任务。现在浏览器的标准中Chrome可以同时支持6个并发连接。

域名分片

既然一个域名可以支持6个长连接,那么可以多分配几个域名。比如content1.runhio.com``content2.runhio.com。这样一个runhio域名下可以分出非常多的二级域名,它们都指向了同样的一台服务器,能够并发的长连接就更多了。

HTTP代理

常见的代理有两种:普通代理隧道代理

普通代理(中间人代理)

img

如图,代理服务器就像一个中间人,帮两边传递信息。不过他可以在中间帮我们过滤、缓存、负载均衡等一些处理。

实际场景中客户端和服务器之间可以有多个代理服务器

隧道代理

客户端通过CONNECT方法请求隧道代理创建一个可以到任意目标服务器和端口号的TCP连接,创建成功之后隧道代理只做请求和响应数据的转发,在中间不做任何处理

img

https服务是需要证书的,而代理服务器显然没有,所以浏览器和代理之间无法创建TLS,所以就有了隧道代理,它把浏览器的数据原样传统,实现了通过中间代理和服务端进行TLS握手,再进行数据加密传输。

代理服务器的好处

  • 突破访问限制:如访问一些单位或集团的内部资源,或用国外代理服务器,也就是翻墙

  • 安全性更高:上网者可以通过这种方式隐藏自己的IP

  • 负载均衡:客户端请求先到代理服务器,而代理服务器后面有多少源服务器,IP是多少,客户端是不知道的。因此,代理服务器收到请求后,根据特定算法把请求分发给不同服务器,让各个源服务器负载尽量均衡

  • 缓存代理:将内容缓存到代理服务器

代理常见的请求头

Via

代理服务器通过Via字段来记录自己的痕迹。举个例子,现在中间有两台代理服务器:

客户端 -> 代理1 -> 代理2 -> 源服务器

在源服务器收到请求后,会在请求头拿到这个字段:

Via: proxy_server1, proxy_server2

而源服务器响应时,最终在客户端会拿到这样的响应头

Via: proxy_server2, proxy_server1

X-Forwarded-For

记录客户端请求的来源IP,每经过一级代理,代理服务器都会把这次请求的来源IP追加进去

X-Forwarded-For: client,proxy1,proxy2

X-Real-IP

不管中间经过多少代理,这个字段始终记录的是客户端最初的IP

X-Forwarded-For的问题

这个字段意味着每经过一个不同的代理,这个字段的名字都要变,从客户端代理1,这个字段是客户端的IP,从代理1代理2又要改变这个字段。

这就会产生两个问题:

  • 代理必须解析HTTP请求头,然后修改,比直接转发数据性能下降
  • HTTPS通信过程中原始报文不允许修改

HTTP缓存

就是将http请求获取的页面资源存储在本地,之后再加载直接从缓存中获取而不用请求服务器,从而响应更快。

强缓存

第一次请求时,服务器把资源的过期时间通过响应头中的ExpiresCache-Control两个字段告诉浏览器,之后再请求这个资源时,会判断有没有过期,没有过期就直接拿来用,不向服务器发起请求,这就是强缓存。

Expires

用来指定资源到期的时间,服务器响应时把它添加到响应头中:

expires: Wed, 22 Nov 2021 08:41:00 GMT

Cache-Control

指定资源过期的时间,如下表示这个请求正确返回的300s内,资料可以使用,否则过期

cache-control:max-age=300

Expires和Cache-Control的区别

  • Expires是HTTP/1.0中的,Cache-Control是HTTP/1.1中的

  • Expires是为了兼容,在不支持HTTP/1.0情况下使用

  • 两者同时存在时,Cache-Control优先级高于Expires

Cache-Control:no-cache

Cache-Control:no-cache并不是代表着不缓存,而是意味着不走强缓存,直接和服务器进行请求一次,进行协商缓存。

Cache-Control:no-store才是代表着不缓存

协商缓存

Last-Modified&If-Modified-Since

在强缓存过期的情况下,我们希望的是在资源文件没有更新的情况下,即使过期了也不会重新获取资源,而是继续使用旧的资源,这个时候就需要走协商缓存。

在第一次请求资源时,服务器除了会返回给浏览器上面说的过期时间,还会在响应头添加Last-Modeified字段,告诉浏览器该资源的最后修改时间

last-modified: Fri, 27 Oct 2021 08:35:57 GMT

然后浏览器再次请求时就会把这个时间再通过另一个字段If-Modified-Since,发送给服务器

if-modified-since: Fri, 27 Oct 2021 08:35:57 GMT

服务器再把这两个字段的时间进行对比,如果一样则说明文件没有被更新,就返回状态码304和空的响应体,浏览器直接拿过期的资源继续使用。

缺点:

  • 如果服务器那边打开了资源文件,即使没有对文件进行修改,但还是会造成Last-Modified被修改,导致不能命中协商缓存
  • 如果资源有周期性的变化,如资源修改后在一个周期内又修改回原来的样子,我们认为这个周期前的缓存还是可以使用的,但Last-Modified不这么认为。

ETag&If-None-Match

为了解决上述问题,引出了ETagIf-None-Match

第一次请求资源时,服务器还会在响应头上返回ETag,这个字段表示的是当前资源文件的一个唯一标识,这个标识由文件内容生成,能精准地感应文件的变化,只要文件内容不同,ETag就会重新生成。

etag: W/"132489-1627839023000"

然后浏览器再次请求的时候就会把这个文件标识,再通过另一个字段If-None-Match,再发送给服务器

if-none-match: W/"132489-1627839023000"

服务器会把两个字段的内容进行比对,如果一样,则说明文件内容并没有改变,那么就说明命中了协商缓存。

Last-Modified和ETag的区别

  • ETag感知文件的精准度要高于Last-Modified

  • 同时使用时,服务器会以ETag优先

  • Last-Modified的性能高于ETag,因为ETag生成过程中需要服务器付出额外开销,会影响服务器性能。

强缓存和协商缓存的区别

  • 优先查找强缓存,没有命中再走协商缓存
  • 强缓存不发请求到服务器,有时候资源更新了浏览器还不知道,但是协商缓存会发请求给服务器去检查资源是否有变更

HTTPS

HTTP缺点

  1. 不具备机密性,HTTP是明文传输的,数据有可能泄露

  2. 不具备真实性,无法认证发送方的身份,有可能是伪造的

  3. 不具备完整性,数据可能被中间人窃取然后篡改

SSL/TLS

HTTPS是超文本传输安全协议,即HTTP+SSL/TLS.

浏览器和服务器通信之前会先进行协商,选出它们都支持的加密套件,用来实现安全的通信。

例如:RSA-PSK-AES128-GCM-SHA256,各算法用途如下图

img

对称加密

所谓对称加密,就是加密和解密使用同一个密钥。

  1. 浏览器给服务器发送一个随机数client-random和一个支持加密的加密方法列表

  2. 服务器给浏览器返回另一个随机数server-random和双方都支持的加密方法

  3. 然后两者用加密方法将两个随机数混合生成密钥,这就是通信双方加解密的密钥

但是对称加密中,将随机数和加密方法直接传送给对方,过程可能会被窃取,别人就能成功解密拿到数据

不对称加密

就是一对密钥,有公钥私钥,其中一个密钥加密后的数据,只能让另一个密钥进行解密。

  1. 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表

  2. 服务器把另一个随机数server-random加密方法公钥传送给浏览器

  3. 浏览器用公钥将两个随机数加密,生成密钥,这个密钥只能由私钥解密

由于公钥反推出私钥的过程,在现在计算机运算能力下是可以做到的,所以非对称密钥至少要2048位才能保证安全性,这就导致了每次通信都需要大计算量去加解密,性能比对称加密要差很多。

TLS的加密

实际上,TLS用的是两种算法的混合加密。通过非对称加密算法交换对称加密算法的密钥,交换之后再全程使用对称加密进行数据传输。

  1. 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表

  2. 服务器把另一个随机数server-random加密方法公钥传回给浏览器

  3. 浏览器又生成另一个随机数pre-random,并用公钥加密后传输给服务器

  4. 服务器用私钥解密,得到pre-random

  5. 浏览器和服务器都将三个随机数用加密方法混合生成最终密钥

这样即使被劫持了,中间人没有私钥就拿不到pre-random,就无法生成最终的密钥。

数字签名

假如在一开始我们就被劫持了,拿到的公钥是中间人的而不是服务器的,数据还是会被窃据,所以数字证书就来了。

数字证书(数字签名)

数字证书需要向有权威的认证机构(CA)获取授权给服务器。首先,服务器CA机构分别有一对密钥(公钥和私钥),数字证书的生成过程:

  • CA机构通过摘要算法生成服务器公钥的摘要

  • CA机构通过CA私钥以及特定签名算法加密上述生成的摘要,生成签名

  • 把签名、服务器公钥打包放入数字签名,并返回给服务器

服务器配置好证书,以后客户端连接服务器,都先把证书发给客户端验证并获取服务器的公钥

证书验证流程

  • 使用CA公钥和声明的签名算法对CA中的签名进行**解密,**得到服务器的公钥的摘要内容
  • 再用摘要算法对证书里面的服务器公钥生成摘要,把这个摘要和上一步得到的摘要进行比对,如果一致则说明证书合法,里面的公钥也是正确的,就可以进行下一步通信

HTTPS如何解决HTTP的缺点

  1. 机密性

信息的机密性HTTPS依靠对称加密和非对称加密来完成,具体参考上述流程

  1. 完整性

信息传输的途中,我们的信息很有可能被第三方进行劫持篡改,通用方法是使用散列算法如MD5将传输内容hash一次得到hash值,即**摘要。**客户端使用密钥对摘要和信息内容进行加密,然后传输给服务端,服务端解密获得原始内容和摘要值,这时服务端使用相同的hash算法对原始内容进行hash,然后把两个hash值进行比对,如果一致则说明信息没有被篡改

  1. 真实性

使用数字证书验证真实性,具体参考上述流程

HTTP和HTTPS的区别

  • HTTP是明文传输,不安全,HTTPS是加密传输的,安全的多

  • HTTP端口号是80,HTTPS端口号是443

  • HTTP不用证书,免费,HTTPS需要认证证书,要钱

  • 连接方式不同,HTTP三次握手,HTTPS中TLS1.2版本要7次,TLS1.3要6次

  • HTTP在应用层,而HTTPS的TLS在传输层

  • HTTP是无状态的,而HTTPS是有状态的,因为TLS这层需要服务器和客户端去缓存密钥,而不是每个请求都执行一次密钥交换

HTTPS连接过程

https比http多了一步TLS连接,TLS连接有以下方式

RSA握手

早期的TLS密钥交换法都是使用RSA算法,它的握手流程如下:

  1. 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表

  2. 服务器把另一个随机数server-random加密方法公钥传给浏览器

  3. 浏览器又生成另一个随机数pre-random,并用公钥加密后传给浏览器

  4. 服务器再用私钥解密,得到pre-random,此时浏览器和服务器都得到了三个随机数,各自将三个随机数用加密方法混合生成最终密钥

RSA弊端

但是如今RSA已经不适用了,因为一旦服务器的私钥泄露了,那么中间人可以通过私钥计算出之前所有报文的secret,破解之前的所有报文。

ECDHE握手

TLS1.2版本用的是ECDHE密钥交换法

img

  1. 浏览器给服务器发送一个随机数client-random,TLS版本和一个支持的加密方法列表

  2. 服务器生成一个椭圆曲线参数server-params、随机数server-random加密方法证书给浏览器

  3. 浏览器又生成椭圆曲线参数client-params,握手数据摘要等信息给服务器

  4. 服务器和浏览器两边得到server-paramsclient-params后用ECDHE算法直接算出pre-random,两边都有三个随机数后,再将三个随机数加密混合生成最终密钥

中间椭圆曲线传递过程没有加密,如果被中间人截获了呢,为什么这样就比RSA安全呢?

答案请看下图!中间传递是两个椭圆参数就是图中所说的公钥Q

img

TLS1.3版本中的握手变成了这样,简化了握手步骤

img

HTTP2

二进制分帧层

HTTP2性能提升的核心在于二进制分帧层。HTTP2是用二进制协议,它采用二进制格式传输数据而不是1.x的文本格式。

img

原来的Headers+Body的报文格式如今被拆分成了一个个二进制的帧,用Header帧存放头部字段,用Data帧存放请求体字段。

三个概念:

  1. 流Stream:已建立的TCP连接上的双向字节流,可以承载一个或多个消息

  2. 消息Message:一个完整的HTTP请求或响应,由一个或多个帧组成,特定消息的帧在同一个流上发送,这就意味着一个HTTP请求或响应只能在一个流上发送

  3. 帧Frame:通信的基本单位

一个TCP连接上可以有任意数量的流

多路复用

HTTP2完美解决了队头阻塞的问题。

HTTP2让所有的通信都在一个TCP连接上完成,真正实现了请求的并发。HTTP2建立一个TCP连接,一个连接上可以有任意多个流,消息分割成一个或多个帧在各自的流里面传输,也就是一个请求一个流,这样就能同时发多个请求了。帧传输过去之后,再进行重组,形成一个完整的请求或响应,这使得所有的请求或响应都不会被阻塞

img

头部压缩

在1.x版本中,首部用文本格式传输,通常会给每个传输增加500-800字节的开销,而有些请求的一些首部字段都是相同的,例如cookie,user-agent等,HTTP2针对首部字段,采用了对应的压缩算法——HPACK。

  • 维护一份相同的静态字典,包含常见的头部名称和值

  • 维护一份相同的动态字典,可以动态地添加内容

  • 通过静态Huffman编码对传输的首部字段进行编码

img

所以在传输首部字段时,例如要传递method:GET,那么只需要传递静态字典里面它对应的索引值就可以了,一个字节搞定。像user-agent、cookie这种静态字典里面只有首部名称而没有值的首部,第一次传输需要user-agent在静态字典中的索引以及他的值,值会采用Huffman编码来减少体积。

第一次传输过user-agent之后,浏览器和服务器会把它添加到自己的动态字典中,后续传输只传对应的索引就好了。

服务器端推送

服务器端推送使得服务器可以预测客户端需要的资源,主动推送到客户端。

例如:客户端请求index.html,服务器端能够额外推送script.jsstyle.css。实现原理就是客户端发出页面请求时,服务器端能够分析这个页面所依赖的其他资源,主动推送到客户端的缓存,当客户端收到原始页面的请求时,它需要的资源已经位于缓存。