【网络篇】Http、Https、Http 2.0 及 DNS

HTTP

HTTP协议是个无状态协议,不会保存状态。

POST和GET的区别

先引入副作用和幂等的概念。
副作用指对服务器上的资源做改变,搜索是无副作用的,注册是副作用的。

幂等指发送M和N次请求(两者不同且都大于1),服务器上资源的状态一致,比如注册10个和11个账号是不幂等的,对文章进行更改10次和11次是幂等的。

在规范的应用场景上说,GET多用于无副作用、幂等的场景,例如搜索关键字。POST多用于副作用、不幂等的场景,例如注册。

在技术上说:

  • GET请求能缓存,POST不能
  • POST相对GET安全一点点,因为GET请求都包含在URL里,且会被浏览器保存历史记录,POST不会,但是在抓包的情况下都是一样的。
  • POST可以通过request body来传输比GET更多的数据,GET没有这个技术
  • URL有长度限制,会影响GET请求,但是这个长度限制是浏览器规定的,不是RFC规定的
  • POST支持更多编码类型且不对数据类型限制

常见状态码

2XX 成功

  • 200 OK,表示从客户端发来的请求在服务器端被正确处理
  • 204 No content,表示请求成功,但响应报文不含实体的主体部分
  • 205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与204不同自傲与要求请求方重置内容
  • 206 Partial Content,进行范围请求

3XX 重定向

  • 301 moved permanently,永久性重定向,表示资源已被分配了新的URL
  • 302 found,临时性重定向,表示资源临时被分配了新的URL
  • 303 see other,表示资源存在着另一个URL,应使用GET方法定向获取资源
  • 304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
  • 307 temporary redirect,临时重定向,同302

4XX 客户端错误

  • 400 bad request,请求报文存在语法错误
  • 401 unauthorized,表示发送的请求需要有通过HTTP认证的认证信息
  • 403 forbidden,表示对请求资源的访问被服务器拒绝
  • 404 not found,表示在服务器上没有找到请求的资源

5XX 服务器错误

  • 500 internal server error,表示服务器端在执行请求时发生了错误
  • 501 Not Implemented,表示服务器不支持当前请求所需要的某个功能
  • 503 service unavailable,表示服务器暂时处于超负载或正在停机维护,无法处理请求

HTTP首部

通用字段 作用
Cache-Control 控制缓存的行为
Connection 浏览器想要优先使用的链接类型,比如keep-alive
Date 创建报文时间
Pragma 报文指令
Via 代理服务器相关信息
Transfer-Encoding 传输编码方式
Upgrade 要求客户端升级协议
Warning 在内容中可能存在错误
请求字段 作用
Accept 能正确接收的媒体类型
Accept-Charset 能正确接收的字符集
Accept-Encoding 能正确接收的编码格式列表
Accept-Language 能正确接收的语言列表
Expect 期待服务端的指定行为
From 请求方邮箱地址
Host 服务器的域名
if-Match 两端资源标记比较
if-Modified-Since 本地资源未修改返回304(比较时间)
if-None-Match 本地资源未修改返回304(比较标记)
User-Agent 客户端信息
Max-Forwards 限制可被代理及王网关转发的次数
Proxy-Authorization 向代理服务器发送验证信息
Range 请求某个内容的一部分
Referer 表示浏览器所访问的前一个页面
TE 传输编码方式
响应字段 作用
Accept-Ranges 是否支持某些种类的范围
Age 资源在代理缓存中存在的时间
ETag 资源标识
Location 客户端重定向到某个URL
Proxy-Authenticate 向代理服务器发送验证信息
Server 服务器名字
WWW-Authenticate 获取资源需要的验证信息
实体字段 作用
Allow 资源的正确请求方式
Content-Encoding 内容的编码格式
Content-Language 内容使用的语言
Content-Length request body 长度
Content-Location 返回数据的备用地址
Content-MD5 Base64加密格式的内容 MD5校验值
Content-Range 内容的位置范围
Content-Type 内容的媒体类型
Expires 内容的过期时间
Last_modified 内容的最后修改时间

HTTPS

HTTPS还是通过了HTTP来传输信息,但是信息通过TLS协议进行了加密。

TLS

TLS协议位于传输层智商,应用层之下。首次进行TLS协议传输需要两个RTT,接下来可以通过Session Resumption 减少到一个RTT。

在TLS中使用了两种加密技术,分别为:对称加密和非对称加密。

对称加密

对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。

非对称加密

有公钥私钥之分,公钥所有人都可以知道,可以将数据用公钥加密,但是将数据解密必须使用私钥解密,私钥只有分发公钥的一方才知道。

TSL握手过程如下:
https://user-gold-cdn.xitu.io/2018/5/12/1635260126b3a10c?w=1558&h=1006&f=webp&s=59424

  1. 客户端发送一个随机值,需要的协议和加密方式
  2. 服务端收到客户端的随机值,自己也产生一个随机值,并根据客户端需求的协议和加密方式来使用对应的方式,发送自己的证书(如果需要验证客户端证书需要说明)
  3. 客户端收到服务端的证书并验证是否有效,验证通过会再生成一个随机值,通过服务端证书的公钥去加密这个随机值并发送给服务端,如果服务端需要验证客户端证书的话会附带证书
  4. 服务端收到加密过的随机值并使用私钥解密获得第三个随机值,这时候两端都拥有了三个随机值,可以通过这三个随机值按照之前约定的加密方式生成密钥,接下来的通信就可以通过该密钥来加密解密。

通过以上步骤可知,在TLS握手阶段,两端使用非对称加密的方式来通信,但是因为非对称加密损耗的性能比对称加密大,所以在正式传输数据时,两端使用对称加密的方式通信。

以上说明的都是TLS 1.2协议的握手情况,在1.3协议中,首次建立连接只需要一个RTT,后面恢复连接不需要RTT了。


HTTP 2.0

HTTP 2.0相比于HTTP 1.X,可以说是大幅度提高了web的性能。

在HTTP 1.X中,为了性能考虑,我们会引入雪碧图、将小图内联、使用多个域名等等的方式。这一切都是因为浏览器限制了同一个域名下的请求数量,当页面中需要请求很多资源的时候,队头阻塞(Head of line blocking)会导致在达到最大请求数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。

在HTTP 1.X中,因为队头阻塞的原因,你会发现请求是这样的
https://user-gold-cdn.xitu.io/2018/5/12/163542c96df8563d?w=518&h=642&f=png&s=72417

在HTTP 2.0中,因为引入了多路复用,你会发现请求是这样的
https://user-gold-cdn.xitu.io/2018/5/12/163542c9d3128c7a?w=900&h=616&f=png&s=71014

二进制传输

HTTP 2.0中所有加强性能的核心点在于此。在之前的HTTP版本中,我们是通过文本的方式传输数据。
在HTTP 2.0中引入了新的编码机制,所有传输的数据都会被分割,并采用二进制格式编码。

https://user-gold-cdn.xitu.io/2018/5/12/163543c25e5e9f23?w=874&h=459&f=png&s=26320

多路复用

在 HTTP 2.0 中,有两个非常重要的概念,分别是帧(frame)和流(stream)。
帧代表着最小的数据单位,每个帧会表示出该帧属于哪个流,流也就是多个帧组成的数据流。

多路复用,就是在一个TCP连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。

Header压缩

在 HTTP 1.X 中,我们使用文本的形式传输header,在header携带cookie的情况下,可能每次都需要重复传输几百到几千的字节。

在 HTTP 2.0 中,使用了HPACK压缩格式对传输的header进行编码,减少了header的大小。并在两端维护了索引表,用于记录出现过的header,后面再传输过程中就可以传输已经记录过的header的键名,对端收到数据后就可以通过键名找到对应的值。

服务端Push

在 HTTP 2.0 中,服务端可以在客户端某个请求后,主动推送其他资源。

可以想象以下情况:
某些资源客户端是一定会请求的,这时就可以采取服务端push的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。当然在浏览器兼容的情况下你也可以使用prefetch。

QUIC

这是一个谷歌出品的基于UDP实现的同为传输层的协议,目标很远大,希望替代TCP协议。

  • 该协议支持多路复用,虽然 HTTP 2.0 也支持多路复用,但是下层仍是TCP,因为TCP的重传机制,只要一个包丢失就得判断丢失包并且重传,导致发生队头阻塞的问题,但是UDP没有这个机制。
  • 实现了自己的加密协议,通过类似TCP的TFO机制可以实现O-RTT,当然TLS 1.3已经实现了O-RTT了
  • 支持重传和纠错机制(向前恢复),在只丢失一个包的情况下不需要重传,使用纠错机制恢复丢失的包
    • 纠错机制:通过异或的方式,算出发出去的数据的异或值并单独发出一个包,服务端在发现有一个包丢失的情况下,通过其他数据包和异或值包算出丢失包
    • 在丢失两个包或以上的情况就使用重传机制,因为算不出来了。

DNS

DNS的作用就是通过域名查询到具体的IP。

因为IP存在数字和英文的组合(IPv6),很不利于人类记忆,所以就出现了域名。你可以把域名看成是某个IP的别名,DNS就是去查询这个别名的真正名称是什么。

在TCP握手之前就已经进行了DNS查询,这个查询是操作系统自己做的。当你在浏览器中想访问www.leeing.site时,会进行以下操作:

  1. 操作系统会首先在本地缓存中查询
  2. 没有的话会去系统配置的DNS服务器中查询
  3. 如果这时候还没得话,会直接去DNS根服务器查询,这一步查询会找出负责site这个一级域名的服务器
  4. 然后去该服务器查询leeing这个二级域名
  5. 接下来三级域名的查询其实是我们配置的,你可以给www这个域名配置一个IP,然后还可以给别的三级域名配置一个IP

以上介绍的是DNS迭代查询,还有种是递归查询,区别就是前者是由客户端去做请求,后者是由系统配置的DNS服务器做请求,得到结果后将数据返回给客户端。

PS:DNS是基于UDP做的查询


从输入URL到页面加载完成的过程?

  1. 首先做DNS查询,如果这一步做了只能DNS解析的话,会提供访问速度最快的IP地址回来
  2. 接下来是TCP握手,应用层会下发数据给传输层,这里TCP协议会指明两端的端口号,然后下发给网络层。网络层中的IP协议会确定IP地址,并且指示了数据传输中如何跳转路由器。然后包会再被封装到数据链路层的数据帧结构中,最后就是物理层面的传输了
  3. TCP握手结束后会进行TLS握手,然后就开始正式的传输数据
  4. 数据在进入服务端之前,可能还会先经过负载均衡的服务器,它的作用就是将请求合理的分发到多台服务器上,这时假设服务端会响应一个HTML文件
  5. 首先浏览器会判断状态码是什么,如果是200那就继续解析,如果是400或500的话就会报错,如果300的话会进行重定向,这里会有个重定向计数器,避免过多次的重定向,超过次数也会报错。
  6. 浏览器开始解析文件,如果是gzip格式的话会先解压一下,然后通过文件的编码格式知道该如何去解码文件。
  7. 文件解码成功后会正式开始渲染流程,先会根据HTML构建DOM树,有CSS的话会去构建CSSOM树。如果遇到script标签的话,会判断是否存在 async 或者 defer ,前者会并行进行下载并执行JS,后者会先下载文件,然后等待HTML解析完成后顺序执行,如果以上都没有,就会阻塞住渲染刘恒直到JS执行完毕。遇到文件下载的会去下载文件,这里如果使用HTTP 2.0协议的话会极大的提高多图的下载效率。
  8. 初始的HTML被完全加载和解析后会触发DOMContentLoaded事件
  9. CSSOM树和DOM树构建完成后会开始生成Render树,这一步就是确定页面元素的布局、样式等等诸多方面的东西
  10. 在生成Render树的过程中,浏览器就开始调用GPU绘制,合成图层,将内容显示在屏幕上了。
坚持原创技术分享,您的支持将鼓励我继续创作!