Lucius's Blog

HTTP 入门体检

无论是大系统还是小项目,无论是移动端还是PC端,无论是大数据还是云计算,从整体到个人,网络协议一直都是绕不过去的坎,它在我们职业生涯中有着举足轻重的地位。技术浪潮一浪接一浪,很多时候我们盲目追求新技术却忘记了新技术的出现都是要依赖于繁琐复杂且难啃的基层技术,新技术只是为了更好更快更稳的开发,针对业务需求相对进行了封装罢了,一层一层剥下来,它还是原来的它。我们先来入门一下 HTTP,OSI模型的应用层。

网络协议层

网络有七层协议层:应用层、表示层、会话层、(安全层 - SSL/TLS)、传输层、网络层、数据链路层、物理层。由于表示层跟会话层没有独立实现过,而是跟应用层一起实现的

应用层

应用层决定了向用户提供应用服务时通信的活动。(DNS、HTTP、HTTPS、RTMP、FTP);

传输层

传输层对上层应用层,提供处于网络连接中的两台计算机之间的数据传输。(TCP、UDP)。

网络层

网络层用来处理在网络上流动的数据包。数据包是网络传输额最小单位。(IP)

链路层

链路层是用来连接网络的硬件部分。包括控制操作系统、驱动、网卡等。

物理层

物理层主要是定义物理设备如何传输数据。

栗子

当我们购物时,会先去 DNS 或 HTTPDNS 查找 IP 地址。知道目标 IP 地址,浏览器就会打包请求,如果使用 HTTPS ,则采取加密传输。

1、应用层:浏览器通过 socket 编程,将其打包传输给下一层传输层;
2、传输层:这里采用TCP协议(PS:它有两个端口,一个是浏览器监听端口,一个是服务器监听端口,操作系统往往通过端口来判断数据包应该往哪个进程走)。TCP将应用层收到的数据包进行~分割~,并在报文上打上标记序号及端口号转发给网络层;
3、网络层:接收到传输层的数据包,在该层有 本地IP地址 以及 目标IP地址,将IP地址封装后转发给链路层;
4、链路层:通过ARP协议,获取本地MAC地址,发送给网关物理层(默认IP:192.168.1.1)
5:物理层:由于有MAC地址,IP 数据包能达到网关。如路由器,会根据路由表,来判断目标 IP 怎么走。

IP 地址:指明了节点被分配到的地址,可变。
MAC 地址:指网卡所属的固定地址,基本不变。
IP 间的通信依赖 MAC 地址。

ARP 协议:解析地址的协议,根据 IP地址 反查出对应的 MAC地址。

HTTP 协议请求报文&响应报文

常见的方法

方法 描述
GET 获取指定资源,一般来说 GET 请求只用于资源数据的请求。
POST 传输实体主体,向指定资源提交数据,如表单提交、资源创建等。
PUT 传输资源,向指定资源位置上传最新内容,如资源更新等。
DELETE 请求服务器删除置顶的 URI 所标识的资源,简单来说就是删除资源。
PATCH 跟 PUT 方法有些类似,都是更新资源。但是 PATCH 主要是更新部分资源, 而 PUT 则是整体更新;当资源不存在时,PATCH 会创建新资源,而 PUT只会 在已有的资源进行更新。
HEAD 同 GET 方法,但 HEAD 常用于获取报文首部,查看服务器性能。
OPTIONS 该方法同 HEAD,但是 OPTIONS 用来询问服务器返回该资源所支持的方法。

常见状态码

状态码大类 状态码小类 描述
1xx 信息性状态码,接收到请求并且继续处理。
2xx 成功状态码。
200 服务器已成功处理了请求。
201 服务器已接收请求,但尚未处理,客户端可以通过该状态码进行轮询。
203 服务器已成功处理了请求,但可能未授权。
204 服务器成功处理了请求,但没有返回任何内容,如删除成功。
206 服务器成功处理了部分 GET 请求,如媒体多端请求。
3xx 重定向状态码。
301 永久性重定向。
302 临时性重定向。
303 同302,但多了一个标准,就是明确要求客户端采用 GET 方法。
注:301、302、303 响应后,浏览器都会把 POST 改为 GET,并删除请求主体,等到再次请求时才发送。
304 资源没有发生变化,该状态码跟重定向没有什么关系。
4xx 客户端错误状态码。
400 请求错误,服务器不理解请求的语法,简单来说就是错误的传参导致的报错。
401 请求不通过身份验证,如未登录或令牌错误。
403 请求通过身份验证,但是未授权,如权限管理越级访问。
404 请求服务器不存在的资源。
405 请求方法不通过,如该用 POST 方法的请求用了 PUT。
406 请求的资源格式不正确,如请求 JSON 格式数据,服务器只有 XML 格式数据。
409 请求发生冲突,常见于修改内容在服务器上是唯一的,如身份证ID。
410 请求的资源曾经存在过,如下架的视频。
413 请求体超过服务器的限制,如上传资源 10M,服务器限制 5M。
414 请求 URI 过长。
415 不支持媒体类型,如上传 PNG 文件,而服务器规定 JPG。
5xx 服务端错误状态码。
500 服务器发生错误,但原因未明。
502 网关错误,如请求需转发到B服务器,而B服务器报错时就会报网关错误。
503 服务不可用,服务器重启或维护之类不在状态。
504 网关超时,同502,只是B服务器久久不回应。

HTTP 首部

q,表示权重值,默认值1.0,区间在0~1。如 Accept-Language:zh-CN,en-US;q=0.8,en;q=0.6,表示浏览器优先支持 zh-CN 。

通用首部字段

通用首部字段指的是请求报文以及响应报文都会使用到的首部。

  • Cache-Control:通过如下指令,来操作缓存的工作机制。未完待续,篇幅太多,不在这里赘述,之后给实例。
常见缓存请求指令 说明
no-cache 强制向服务器再次验证
no-store 不缓存请求或响应的任何内容
max-age=(秒) 响应的最大 Age 值
max-stale=[秒] 接收已过期的响应
min-fresh=(秒) 期望在指定时间内的响应仍有效
常见缓存响应指令 说明
public 可向任意方提供响应的缓存
private 仅向特定用户返回响应
no-cache 缓存前必须先确认其有效性
no-store 不缓存请求或响应的任何内容
max-age=(秒) 响应的最大 Age 值
s-maxage=(秒) 公共缓存服务器响应的最大 Age 值
must-revalidate 可缓存但必须再向源服务器进行确认
  • Connection:Connection 本身只与当前连接有关,当客户端与服务器之间存在代理,那么从客户端的请求报文会逐段发给服务器,服务器也会逐段返回客户端,通常就算有层层代理请求头以及响应头都会保持原封不动。但是刚才提到,Connection 只与当前连接有关,那么在报文转给下个节点之前删除,否则就会出现不可预期的问题。其他不传递的 Header 可以看Connection 的 hop-by-hop
    • Connection: Close:断开时将 Connection 设置为Close;
    • Connection: Keep-Alive:连接保持持久化;
  • Date:创建报文的日期时间;
  • Pragma:no-cache。指令唯一,为兼容 HTTP/1.1 之前的版本;
  • Trailer:简单来说,该字段主要是说明报文末尾记录了哪些字段;
  • Transfer-Encoding:传输编码方式,如 chunk;
  • Upgrade:升级为其他的协议;
1
2
Upgrade: TLS/1.0
Connection: Upgrade (必须指定为Upgrade)

请求首部字段

  • Accept:客户端能处理的媒体类型,如text/htmlimage/jpeg
  • Accept-Charset:内容支持的字符集,如ios-8895-5,utf-8;q=0.8
  • Accept-Encoding:内容支持的编码,如gzip,deflate
  • Accept-Language:内容支持的语言,如zh-cn,zh;q=0.7
  • Authorization:认证信息,用来认证用户的身份;
  • Host:请求资源的服务器,如www.baidu.com
  • If-Match / If-Modified-Since / If-None-Match:参考缓存机制;
  • If-Range:资源未更新时发送实体 Byte 的范围请求,如 If-Range 字段值若是跟 ETag 值或更新日期时间匹配一致,那么就作为范围请求处理,若不一致,则返回全部资源;
1
2
3
4
5
6
7
8
9
10
11
12
// request body
GET /index.html
If-Range: "123456"
Range: bytes=5001-10000

// response body(匹配情况下)
206 Partial Content
Content-Range: bytes 5001-10000/1000

// response body(不匹配情况下)
200 OK
ETag: "45678"
  • Range:获取部分范围资源请求,服务器接收后会返回 206 状态码;
  • Referer:告知服务器请求的原始资源的 URI;
  • User-Agent:将创建请求的浏览器和用户代理名称等信息传送给服务器。
  • Via:用来追踪客户端与服务器之间的请求和响应报文的传输路径;
  • Warning:错误通知;

响应首部字段

  • Accept-Ranges:bytes 和 none。bytes 是用来告知客户端,服务器是否能处理范围请求;
  • Age:告知客户端,服务器在多久前创建了响应,单位为秒。若响应的为缓存服务器,Age 是指缓存后的响应再次发起认证到认证完成的时间
  • ETag:资源的唯一标志,当资源更新,资源的标志也会随之更新;
    • 强ETag:实体发生多么细微的变化都会改变值;
    • 弱ETag:只有资源发生根本变化,产生差异才会改变,这时会在开始附加 W/,如:ETag: W/"xxx-1234"
  • Location:将客户端重定向至指定 URI;
  • Retry-After:对再次发起请求的时机要求,单位秒,常配合状态码 503 或 3xx 重定向,如Retry-After: 120
  • Server:当前服务器上的HTTP服务器应用程序信息,如Server: Apache/xxxx (Unix)
  • Vary:可对缓存进行控制,源服务器会向代理服务器传达关于本地缓存使用方法的命令,简单来说,就是指定不可缓存的请求头列表。

实体首部字段

实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息,这里主要列举下响应报文补充字段

  • Allow:用于通知客户端能够支持 Request-URI 指定资源 的所有 HTTP 方法,当服务器收不到不支持的 HTTP 方法时,会以 405 状态码返回。与此同时,还会把所有支持的 HTTP 方法写入首部字段 Allow 后返回。
  • Content-Encoding:告知客户端服务器对实体内容的编码方式,有gzip、compress、deflate、identity;
  • Content-Language:告知客户端实体内容使用的自然语言,如 zh-cn
  • Content-Length:实体内容的大小(单位字节);
  • Content-Location:返回资源对应的 URI,如访问 https://www.baidu.com/,返回资源 https://www.baidu.com/index.html
  • Content-Range:范围请求,如 Content-Range: bytes 5001-10000/10000,单位字节;
  • Content-Type:同 Accept
  • Expires:资源的实效日期,但是假如首部字段 Cache-Control 有指定 max-age 指令时,会优先处理 max-age
  • Last-Modified:资源最后的修改时间;

其他常用响应首部字段 X-

  • X-Frame-Options:控制网站内容在其他 Web 网站的 Frame 标签内的显示问题。DENY为拒绝;SAMEORIGIN:尽在同源域名下匹配时许可;
  • X-XSS-Protection:针对跨站脚本攻击的一种对策,0 为将XSS过滤设置成无效状态,1 则相反;
  • Content-Security-Policy,X-Content-Security-Policy:内容安全策略,为了防御XSS、CSRF等代码注入攻击,阻止恶意内容在源网页中执行;
  • X-UA-Compatible:推荐指定的渲染引擎来展示网站内容;

其他常用请求首部字段 X-

  • X-Requested-With:主要用于标识 Ajax 请求。大部分的JavaScript框架会发送这个字段,如 X-Requested-With: XMLHttpRequest
  • DNT:同 X-Do-Not-Track,请求某个网页应用程序停止跟踪某个用户。0 表示 DNT 被禁用,1 则相反;
  • X-Csrf-Token:用于防止 CSRF 攻击,如 X-Csrf-Token:i8XNjC4b8KVok4uw5RftR38Wgp2BFwql

HTTP 协议通信

在 HTTP 1.1 之前,每个 HTTP 请求都要求打开一次 TCP 连接,并且使用一次之后就断开这个 TCP 连接,每次这样都会造成资源的浪费。

持久连接

HTTP/1.1 keep-alive:只要任意一端没有明确提出断开连接,则保持 TCP 连接状态,即在一次 TCP 连接中可以持续发送多份数据而不会断开连接,这样就可以减少 TCP 连接建立的次数,意味着可以减少 TIME_WAIT 状态连接。但是,长时间的 TCP 连接容易导致系统资源无效占用,所以正确地设置 keep-alive timeout 时间非常重要。

为什么需要持久连接?为什么 TCP 的建立耗费时间?这里就需要说到 TCP 的三次握手跟四次挥手了。

TCP 三次握手

在客户端和服务器建立 HTTP 请求的发送和返回的过程中,在这过程中是需要创建 TCP Connection,因为 HTTP 只有请求和响应这个概念,而 TCP 起到了传输数据包的作用。在 HTTP 1.0 版本,TCP 传输完毕之后就关闭了,而在 HTTP 1.1 版本,则 TCP 上面是可以有多个 HTTP 请求的。

seq(Sequence Number):序列号;
ack(Acknowledgement Number):确认序号

  1. SYN=1, seq=X:客户端发送一个 TCP 的 SYN 标志位为1的包,指明客户端准备连接服务器的端口。而 seq,为初始序列号X,X是随机的,这样为了网络安全。发送完毕之后客户端就进入 SYN_SEND 状态;
  2. SYN=1, ACK=1, seq=y, ack=x+1:服务器返回确认包(SYN=1, ACK=1),同时服务器随机生成 seq 序列号,并将确认序号 ack 设置为客户请求序号加1,即 ack=x+1。完毕之后,服务器进入 SYN_RCVD 状态;
  3. ACK=1, ack=y+1, seq=x+1:客户端收到服务器的数据后,会检查 ack 是否等于 x+1,ACK标志位为1。如果正确则会再次发送确认包(ACK=1),并且把服务器发来的 ack 序号在 seq 的基础上加1,即 ack=y+1,然后再设置 seq=x+1。发送完毕后,客户端和服务器都进入了 ESTABLISHED 状态,TCP握手结束。

TCP 四次挥手

关闭TCP连接,无论是客户端还是服务器,只要执行 close 操作,就可以发起挥手行为。之所以有4次,是因为 TCP 连接的拆除需要发送4个包。我们在以下视图默认为客户端向服务器发起 close 操作。其中seq/ack同上。

  1. FIN=1, seq=x:客户端发送 FIN 包,表示客户端已经没有数据可以发送了,但是仍然可以接收数据,这时候客户端进入 FIN+WAIT_1 状态;
  2. ACK=1, ack=X+1:服务器收到客户端的 FIN 包,随后反手就是一个确认包,表示服务器已经收到客户端关闭连接的请求,但是还没做到真正的关闭;
  3. FIN=1, seq=y:服务器准备关闭连接时,再次向客户端发送结束连接的响应。发送完毕之后,服务器进入 LAST_ACK 状态,等待客户端最后的确认包ACK
  4. ACK=1, ack=y+1:客户端收到服务器的结束响应,然后客户端就发送最后的确认包 ACK,服务器收到后就开始关闭连接,进入 CLOSED 状态;客户端等待 2MSL(MSL(Maximum Segment Lifetime): 报文段最大生存时间)后,再也没有收到服务器的 ACK,认为服务器已经正常关闭了,随后客户端也关闭连接,进入CLOSED 状态。

HTTPS

不仅仅 HTTP,任何未加密的协议都存在以下的不足:

  • 通信使用不加密明文,内容可能会被窃听;
  • 不验证通信方的身份,有可能遭遇伪装;
  • 无法证明报文的完整性,所以有可能已遭篡改;

-> HTTP 加密处理 + 认证 + 完整性保护 = HTTPS
在上面提到网络协议层的时候,有一层是安全层,该层就是 SSL协议/TLS协议。HTTP 是直接与TCP通信,而HTTPS,则演变成了先和 SSL 通信,再由 SSL 和 TCP 通信了。

SSL 还可以配合其他应用层协议,如SMTP,Telnet;

HTTPS 加密方式

加密和解密共用一个密钥称为对称加密,而使用公开密钥+私有密钥则为非对称加密

HTTPS 则采用对称加密和非对称加密两者并用的混合加密机制。因为无论是对称加密还是非对称加密,都是无法直接保证通信的安全性,如无法证明公开密钥就是货真价实的。因此需要数字证书认证机构

证书申请流程

  1. 服务器运营人员向数字证书认证机构提出公开密钥申请
  2. 机构判明申请者的身份后,对公开密钥做数字签名,然后将其跟公钥证书绑定在一起;
  3. 服务器将该公钥证书发给客户端,以进行加密通信;
  4. 客户端对证书上的数字签名进行验证,验证其有效且信赖

多数浏览器开发商发布版本会事先植入常用认证机关的公开密钥。

通信机制

  1. Client Hello 报文:包含SSL指定版本、加密组件(Cipher Suite)、列表(密钥长度、加密算法等);
  2. Server Hello 报文:同 Client Hello 报文,在报文中包含 SSL 版本以及加密组件(筛选自 Client Hello 报文);
  3. Certificate 报文:包含公开密钥证书;
  4. Client Key Exchange 报文:步骤3的公开密钥已对该报文进行加密,并含有 Pre-master secret 的随机字符串;
  5. Change Cipher Spec 报文:该报文会提示服务器,此报文后的通信采用 Pre-master secret密钥加密;
  6. Finished 报文:包含连接至今为止的所有校验值;
  7. 到这一步说明 Finished 报文交换完毕,SSL 连接建立完成,开始 HTTP 通信;

在应用层发送数据时会附加 MAC(Message Authentication Code)的报文摘要来检查报文是否遭到篡改,从而保护报文的完整性。

安全性在网络通信得到了保证,但是HTTPS也存在HTTPS 处理速度慢(SSL 通信慢,而且消耗CUP和内存资源)以及证书认证贵 的缺点。

HTTP 1.1 与 HTTP 2

在这里简单的说下,相比之下,HTTP 1.1 和 HTTP 2有什么优化。

HTTP 1.1

  1. 持久连接:由于创建 HTTP 连接需要三次握手,并且在每一次请求时需要在客户端和服务器之间创建 TCP 连接, 在服务器返回完内容后,该 TCP 连接就关闭,这样就会导致资源的浪费。因此 HTTP 1.1 的持久连接,就会再每一次请求建立完 HTTP 连接后不关闭;
  2. pipeline:可以在同一个连接发送多个请求。虽然说是可以发送多个,但是服务器接收处理的逻辑,依旧是并行的,所以返回的数据依旧是需要等待服务器处理完毕再进行下一个的;
  3. 增加了首部字段和方法:如Host首部字段、OPTION请求方法;

HTTP 是一种不保存状态,即无状态协议,它不会对请求和响应做持久化处理。因此才会有了Cookie、Session技术的引进。

Session的实现对Cookie有依赖关系,前者是保存在服务器,因为会占用服务器CPU和内存资源,但是相对安全;相反的后者是保存在客户端的,在响应报文内携带Set-Cookie首部字段,告知客户端保存,而且安全性较弱。

HTTP 2

  1. 二进制数据传输:在之前的 HTTP 版本,大部分的数据传输是字符串,而在 HTTP 2 则会以数据帧来进行传输(有点像websocket),这样同一个连接里的多个请求就不需要按照顺序来处理了;
  2. 头信息压缩提高效率优化:在 HTTP 1.1版本,每一次的发送跟接收,头信息都需要完整的返回,因此会占用服务器资源以及带宽资源,因此压缩完后就可以提高利用率。
  3. 推送:在之前的 HTTP 版本,都是客户端向服务器发送请求,而在 HTTP 2,服务器也可以主动的向客户端发送数据传输。

总结

有关网络协议知识点太多了,在这里也只是借用巨人的肩膀来简单的理清网络协议的大概思路。每一个细节,每一个原理真真正正要较真起来,都可以单独写一篇文章,之所以有这篇文章的存在,是因为后续的文章都需要或多或少的网络协议知识,也是为了以后方便自己记忆,不用到处查找资料。这里的知识点可能会有所纰漏错误,也有可能在这里说得不明不白模糊不清,这之后会慢慢优化补上。

参考

我只是试下能不能被赞赏😳