一、TCP
1、TCP协议
TCP是一个可靠的,面向连接的,面向字节流、全双工的协议。发送端在发送数据以后,启动一个定时器,如果超时没有收到对端确认会进行重传,接收端利用序·
- 可靠的: TCP 是在 IP 的基础上构建的传输协议,而 IP 是一种无连接不可靠的协议,它尽最大可能将数据报从发送者传输给接收者,但并不保证包到达的顺序会与它们被传输的顺序一致,也不保证包是否重复,甚至都不保证包是否会达到接收者。所以TCP他必须通过自身的机制来保障自己的可靠性,从五个方面入手
- 对每个包进行校验和:每个TCP包首部中都有两个字节用来表示校验和,防止在传输过程中有损坏。如果收到一个校验和有差错的报文,TCP 不会发送任何确认直接丢弃它,等待发送端重传。
- 通过包的序列号保证了接收数据的乱序和重复问题:在TCP的包首部中有32位的确认序号,假设我们TCP发三个数据包,因为网络的原因导致第二个、第三个包先到接收端,第一个包最后到,接收端不会因为到达顺序和发出顺序不一样就把包弄错,TCP 会根据他们的序号进行重新的排列然后把结果传递给上层应用程序。如果 TCP 接收到重复的数据,可能的原因是超时重传了两次但这个包并没有丢失,接收端会收到两次同样的数据,它能够根据包序号丢弃重复的数据。
- 、超时重传:TCP 发送数据后会启动一个定时器,等待对端确认收到这个数据包。如果在指定的时间内没有收到 ACK 确认,就会重传数据包,然后等待更长时间,如果还没有收到就再重传,在多次重传仍然失败以后,TCP 会放弃这个包。
- 流量控制:
- 拥塞控制:
- 面向连接:就是在发送数据之前需要通过「握手」建立一个逻辑连接,结束通信时也是通过有序的四次挥手来断开连接。
- 字节流: 当TCP在传输层发送消息时,一个消息可能会被分割成多个TCP报文进行转发给网络层。我们不能认为一个TCP报文就是一个消息,所以TCP是面向字节流协议
- 全双工: 在 TCP 中发送端和接收端可以是客户端/服务端,也可以是服务器/客户端,通信的双方在任意时刻既可以是接收数据也可以是发送数据,每个方向的数据流都独立管理序列号、滑动窗口大小、MSS 等信息。
UDP
TCP 是一个有状态的协议,需要先与对方建立连接然后才能发送数据,而且保证数据不丢失不重复。而 UDP 则比较简单,它无状态,不用事先建立连接就可以任意发送数据,但不保证数据一定会发到对方。两个协议的另一个重要区别在于数据的形式。TCP 的数据是连续的“字节流”,有先后顺序,而 UDP 则是分散的小数据包,是顺序发,乱序收。
2、TCP首部
1、序列号
TCP 是面向字节流的协议,通过 TCP 传输的字节流的每个字节都分配了序列号,序列号(Sequence number)指的是本报文段第一个字节的序列号。
序列号加上报文的长度,就可以确定传输的是哪一段数据。序列号是一个 32 位的无符号整数,达到 2^32-1 后循环到 0
在 SYN 报文中,序列号用于交换彼此的初始序列号,在其它报文中,序列号用于保证包的顺序,在其它报文中,序列号用于保证包的顺序
因为网络层(IP 层)不保证包的顺序,TCP 协议利用序列号来解决网络包乱序、重复的问题,以保证数据包以正确的顺序组装传递给上层应用。
初始序列号
在建立连接之初,通信双方都会各自选择一个序列号,称之为初始序列号。在建立连接时,通信双方通过 SYN 报文交换彼此的 初始序列号
初始序列号是通过源地址、目标地址、源端口、目标端口和一个随机有因子通过MD5进行计算出来的,因为我们的 MD5 其实是一种摘要算法,如果仅有这几个因子的话,其实初始序列是很有可能相同的,所以我们就是把 MD5 算出来的结果加上时间因子,这样初始序列号就不会重复了
2、确认号
TCP 使用确认号(ACK)来告知对方下一个期望接收的序列号,小于此确认号的所有字节都已经收到
- 不是所有的包都需要确认的
- 不是收到了数据包就立马需要确认的,可以延迟一会再确认
- ACK 包本身不需要被确认,否则就会无穷无尽死循环了
- 确认号永远是表示小于此确认号的字节都已经收到
3、TCP 标记
TCP 有很多种标记,有些用来发起连接同步初始序列号,有些用来确认数据包,还有些用来结束连接。TCP 定义了一个 8 位的字段用来表示 flags,大部分都只用到了后 6 个
我们通常所说的 SYN、ACK、FIN、RST 其实只是把 flags 对应的 bit 位置为 1 而已,这些标记可以组合使用,比如 SYN+ACK,FIN+ACK 等
- SYN(Synchronize):用于发起连接数据包同步双方的初始序列号
- ACK(Acknowledge):确认数据包
- RST(Reset):这个标记用来强制断开连接,通常是之前建立的连接已经不在了、包不合法、或者实在无能为力处理
- FIN(Finish):通知对方我发完了所有数据,准备断开连接,后面我不会再发数据包给你了。
- PSH(Push):告知对方这些数据包收到以后应该马上交给上层应用,不能缓存起来
4、MSS (TCP 允许接收的最大报文段)
TCP 会主动把数据分割成小段再交给网络层,最大的分段大小称之为 MSS,为了避免被发送方分片
这样一个 MSS 的数据恰好能装进一个 MTU 而不用分片
- 数据链路层传输的帧大小是有限制的,不能把一个太大的包直接塞给链路层,这个限制被称为「最大传输单元(Maximum Transmission Unit, MTU)」
3、TCP 三次握手
三次握手的目的是为了交换客户端和服务端的初始序列号
第一次握手:
客户端首先会确定一个初始序列号,然后会向服务端发送一个 SYN 报文,这个报文的 SYN 标记被置位,这个 SYN 报文的序列号就是我们的初始序列号,第一次握手的作用就是让服务端直到客户端的初始序列号
SYN 报文不携带数据,但是需要被确认,所以是会消耗一个序列号,下次发送数据序列号要加一
第二次握手:
服务端也会确认一个自己的初始序列号,然后向客户端发送一个 SYN 报文和一个 ACK 报文,这个 SYN 报文的作用就是告知客户端服务端的初始序列号;ACK 报文的作用是告诉客户端说,我收到你发的 SYN 报文了,你的下一个报文要从 SYN 的序列号+1开始发
ACK 报文不携带数据,并且不需要被确认,所以不会消耗序列号,只会占用一个序列号,他用完之后,下一个报文可以接着用
第三次握手:
客户端收到了服务端发送的 SYN 报文之后,也会发一个 ACK 报文来进行确认;
4、TCP 四次挥手
第一次挥手:
客户端会发送一个 FIN 报文给服务端,FIN 报文的作用就是告诉对方,我发完了所有数据,准备断开连接,后面我不会再发数据包给你了。FIN 报文其实就是将 FIN 标志位设置为 1。发完 FIN 报文之后,客户端就不能再发送数据给服务端了,但还可以接收服务端的数据
FIN 报文时可以携带数据的,客户端可以在发送最后一个数据块的时候把 FIN 报文给捎上;也可以不带数据,都会消耗一个序列号
第二次挥手:
服务端收到客户端发的 FIN 报文之后,会发一个 ACK 报文给 客户端,就是告诉客户端说我知道你准备关闭了
第三次挥手:
服务端也没有数据要发了,就会给客户端发一个 FIN 报文,然后等待客户端进行确认
第四次挥手:
客户端收到服务端的 FIN 报文以后,回复 ACK 报文用来确认第三步里的 FIN 报文,进入TIME_WAIT 状态,等待 2 个 MSL 以后进入 CLOSED 状态。服务端收到 ACK 以后进入CLOSED 状态。
MSL:
MSL 是 TCP 报文在网络中的最大生存时间
为什么要等待两个 MSL / TIME_WAIT 存在的原因是什么:
- 假如服务端给客户端发送了一个报文,因为网络延迟,迟迟没有到达,这个时候客户端直接进入
CLOSED 状态。然后客户端和原来的服务端又建立的一条 TCP 连接,开始发送数据,这个时候,之前的报文到了,就会造成数据的混乱;等待两个 MSL,保证了在创建新的 TCP 连接以后,老连接姗姗来迟的包已经在网络中被丢弃消逝,不会干扰新的连接。 - 关闭连接的四次挥手中,最终的 ACK 由主动关闭方发出,如果这个 ACK 丢失,对端(被动关闭方)将重发 FIN,如果主动关闭方不维持 TIME_WAIT 直接进入 CLOSED 状态,则无法重传 ACK,被动关闭方因此不能及时可靠释放。
为什么是两个 MSL:
- 1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端
- 1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达
5、TCP 超时重传
TCP 发送数据后会启动一个定时器,等待对端确认收到这个数据包。如果在指定的时间内没有收到 ACK 确认,就会重传数据包,然后等待更长时间,如果还没有收到就再重传,在多次重传仍然失败以后,TCP 会放弃这个包。
1、快重传机制
当发送端收到 3 个或以上重复 ACK,就意识到之前发的包可能丢了,于是马上进行重传,不用傻傻的等到超时再重传
6、TCP 流量控制【滑动窗口】
流量处理防止发送端向接收端过多的发送数据
滑动窗口的本质就是接收缓冲区空闲的空间,接收端会通过ACK包来告诉发送端窗口的大小,发送端根据窗口的大小来发送数据达到流量控制的目的
TCP 会把要发送的数据放入发送缓冲区(Send Buffer),接收到的数据放入接收缓冲区(Receive Buffer),会不停的读取接收缓冲区的内容进行处理。
流量控制做的事情就是,如果接收缓冲区已满,发送端应该停止发送数据;为了控制发送端的速率,接收端通过 ACK 包来告诉客户端自己的接收窗口,就是接收缓冲区的空闲部分,发送端要根据这个值调整自己的发送策略
ACK 包里面会告诉发送端接收端的窗口的大小,比如说win=3000,发送端收到这个 ACK 包之后,会把自己的发送窗口限制在3000之内,如果这个值win=0,发送端就应该停止发送数据
7、TCP 拥塞控制
流量处理只能防止发送端向接收端过多的发送数据,有考虑整个网络的通信状况,所以需要拥塞控制,拥塞控制从整个网络的层面去控制数据的发送
主要涉及到四个算法:
为了实现上面的算法,TCP 的每条连接都要维护两个值:
拥塞控制其实就是通过这四种算法来控制拥塞窗口的变化
7.1、拥塞窗口
拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个
如果接收窗口比拥塞窗口小,表示接收端处理能力不够。如果拥塞窗口小于接收窗口,表示接收端处理能力 ok,但网络拥塞。
拥塞控制的算法的本质是控制拥塞窗口(cwnd)的变化
7.2、慢启动
在 TCP 连接建立之初,发送端是不知道接收端有多快,如果是一个缓慢的网络,发送端一下发送大量的数据,就会导致更大的网络延迟。
所以每个 TCP 连接都有一个拥塞窗口的限制,最初整个值很小,随着时间的推移,每次发送的数据量慢慢递增,这种机制就叫慢启动
慢启动算法的过程如下:
- 第一步,三次握手以后,双方通过 ACK 告诉了对方自己的接收窗口(rwnd)的大小,之后就可以互相发数据了
- 第二步,通信双方各自初始化自己的「拥塞窗口」(Congestion Window,cwnd)大小。
- 第三步,cwnd 初始值较小时,每收到一个 ACK,cwnd + 1,每经过一个 RTT,cwnd 变为之前的两倍。
TCP 在发送一个包时,会记录这个包的发送的时间 t1,用收到这个包的确认包时 t2 减去 t1 就可以得到这次的 RTT。
拥塞窗口的大小肯定不能就一直增长,我们通过慢启动阈值来控制,当拥塞窗口大小小于慢启动阈值时,拥塞窗口按指数级增长;当大于慢启动阈值后,按线性增长,这就是拥塞避免
7.3、拥塞避免
当我们的拥塞窗口大于慢启动阈值时,就会进入拥塞避免阶段,每次增加一个 MSS,直到检测到拥塞为止;MSS是TCP允许接收的最大报文段;
与慢启动的区别在于
- 慢启动的做法是 RTT 时间内每收到一个 ACK,拥塞窗口 cwnd 就加 1,也就是每经过 1 个 RTT,cwnd 翻倍
- 拥塞避免的做法保守的多,每经过一个RTT 才将拥塞窗口加 1,不管期间收到多少个 ACK
7.4、快速重传
重传的时间间隔,要等几百毫秒才会进行第一次重传,并且重传的时候,TCP 将会使用定时器来要求传输暂停。在暂停的这段时间内,没有新的或复制的数据包被发送。,所以有了快速重传
当接收端收到一个不按序到达的数据段时,TCP 立刻发送 1 个重复 ACK,当发送端收到 3 个或以上重复 ACK,就意识到之前发的包可能丢了,于是马上进行重传,不用傻傻的等到重传定时器超时再重传。
选择确认(SACK)
快速重传解决了重传问题,但又引出了一个新的问题,那就是,丢失的那个包之后发出去的包也有可能丢失,到底是重传丢的包还是都重传呢,选择确认解决了这个问题
选择确认在发重复ACK的包时,会把接收端后续接收到的包告诉发送端,这样发送端就知道后续的包已经被接收端收到,只有重传丢失的包就行了
7.5、快速恢复
当收到三次重复 ACK 时,进入快速恢复阶段,这阶段可以理解为网络轻度拥塞。
- 拥塞阈值 降低为 拥塞窗口 的一半:ssthresh = cwnd / 2
- 拥塞窗口 cwnd 设置为 拥塞阈值
- 拥塞窗口线性增加
8、Nagle 算法
Nagle 算法作用是减少发送端频繁的发送小包给对方
Nagle 算法是应用在发送端的,简而言之就是,对发送端而言:
- 当第一次发送数据时不用等待,就算是 1byte 的小包也立即发送
- 后面发送数据时需要累积数据包直到满足下面的条件之一才会继续发送数据:
- 数据包达到最大段大小MSS
- 接收端收到之前数据包的确认 ACK
Nagle 算法可以使得不再那么频繁的发送小包,而是合并到一起,代价是稍微有一些延迟。
而且,Nagle 算法和延迟确认一起使用会出现很严重的性能问题了。Nagle 攒着包一次发一个,延迟确认收到包不马上回。
9、延迟确认
如果收到一个数据包以后暂时没有数据要分给对端,它可以等一段时间(Linux 上是 40ms)再确认。如果这段时间刚好有数据要传给对端,ACK 就可以随着数据一起发出去了。如果超过时间还没有数据要发送,也发送 ACK,以免对端以为丢包了。这种方式成为「延迟确认」。
这个原因跟 Nagle 算法其实一样,回复一个空的 ACK 太浪费了。
- 如果接收端这个时候恰好有数据要回复客户端,那么 ACK 搭上顺风车一块发送。
- 如果期间又有客户端的数据传过来,那可以把多次 ACK 合并成一个立刻发送出去
- 如果一段时间没有顺风车,那么没办法,不能让接收端等太久,一个空包也得发。
这种机制被称为延迟确认
10、TCP 的 keepalive 机制
网络故障或者系统宕机都将使得对端无法得知这个消息。如果应用程序不发送数据,可能永远无法得知该连接已经失效。假设应用程序是一个 web 服务器,客户端发出三次握手以后故障宕机或被踢掉网线,对于 web 服务器而已,下一个数据包将永远无法到来,但是它一无所知
TCP 协议的设计者考虑到了这种检测长时间死连接的需求,于是乎设计了 keepalive 机制。
二、HTTP
1、HTTP
HTTP 是超文本传输协议其实就是一种约定,约定了计算机之间的交流通信的规范,还有各种控制和错误处理的方式,交流通信其实就是传输数据,它传输的数据不像 TCP 一样传输的是二进制包,HTTP 传输的能够被浏览器服务器处理的完整的有意义的数据,比如我们的HTML
HTTP 通常跑在 TCP/IP 协议栈之上,依靠 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。
CDN
浏览器不会说直接连到服务器,中间会有 CDN,主要起到缓存加速的作用
CDN 可以缓存源站的数据,让浏览器的请求不用“千里迢迢”地到达源站服务器,直接在“半路”就可以获取响应。
HTTP 与 TCP 的关系
TCP 是传输控制协议,基于 IP 协议来提供可靠的字节流形式的通信,是 HTTP 的基础,HTTP 不关心传输的细节,其实是运行在了 TCP 协议上
TCP 是 HTTP 的下层协议,负责具体的数据传输
DNS(域名系统)
在 TCP/IP 协议中使用 IP 地址来标识计算机,数字形式的地址对于计算机来说是方便了,但是对人来说,数字不好记
DNS 就是用有意义名字来代替IP地址那一串数字,就叫做域名
但是我们用 TCP/IP 协议来通信仍然要使用 IP 地址,所以需要把域名做一个转换,“映射”到它的真实 IP,这就是所谓的“域名解析”
URI/URL
DNS 和 IP 地址只是标记了互联网上的主机,但主机上有很多多文本、图片、页面,我们需要用 URI(统一资源标识符),来唯一的标记互联网上的资源
URL, 统一资源定位符,也就是我们俗称的“网址”,它实际上是 URI 的一个子集,不过因为这两者几乎是相同的,差异不大,所以通常不会做严格的区分。
URI 主要有三个基本的部分构成:
- 协议名:即访问该资源应当使用的协议,在这里是“http”;
- 主机名:即互联网上主机的标记,可以是域名或 IP 地址,在这里是“nginx.org”;
- 路径:即资源在主机上的位置,使用“/”分隔多级目录,在这里是“/en/download.html”。
HTTPS
HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,为 HTTP 套了一个安全的外壳;
2、协议分层
2.1、TCP/IP 网络分层模型(四层)
- **链接层:**负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标记网络上的设备,所以有时候也叫 MAC 层。
- **网际层:**IP 协议就处在这一层。因为 IP 协议定义了“IP 地址”的概念,所以就可以在“链接层”的基础上,用 IP 地址取代 MAC 地址,把许许多多的局域网、广域网连接成一个虚拟的巨大网络,在这个网络里找设备时只要把 IP 地址再“翻译”成 MAC 地址就可以了。
- **传输层:**这个层次协议的职责是保证数据在 IP 地址标记的两点之间“可靠”地传输,是 TCP 协议工作的层次,还有 UDP
- **应用层:**HTTP
MAC 层的传输单位是帧(frame),IP 层的传输单位是包(packet),TCP 层的传输单位是段(segment),HTTP 的传输单位则是消息或报文(message)。但这些名词并没有什么本质的区分,可以统称为数据包。
2.2、OSI 网络分层模型(七层)
- 第一层:物理层,网络的物理形式,例如电缆、光纤、网卡、集线器等等;
- 第二层:数据链路层,它基本相当于 TCP/IP 的链接层;
- 第三层:网络层,相当于 TCP/IP 里的网际层;第四层:传输层,相当于 TCP/IP 里的传输层;
- 第五层:会话层,维护网络中的连接状态,即保持会话和同步;
- 第六层:表示层,把数据转换为合适、可理解的语法和语义;
- 第七层:应用层,面向具体的应用传输数据。
2.3、TCP/IP 协议栈的工作方式
HTTP 利用 TCP/IP 协议栈传输数据可以想象成一个发快递的过程
假设你要发一个快递给同学,你要先把东西包起来,这个东西就是 HTTP 要传输的内容,比如 HTML,包起来就相当于是 HTTP 协议为它加了一个 HTTP 专用附加数据
然后把快递交给快递员,快递员会给快读套个盒子,贴快递单号,相当于在 TCP 层给数据再次打包,加上了 TCP 头。
接着快递小哥,把快递运到集散点,然后再装进更大的卡车里,相当于在 IP 层、MAC 层对 TCP 数据包加上了 IP 头、MAC 头。
到了另外一个城市,就要卸货,相当于是在 IP 层、MAC 层传输后拆包。
递员到了你朋友的家门口,撕掉标签,去除了 TCP 层的头,你朋友再拆掉塑料袋包装,也就是 HTTP 头,最后就拿到了玩具,也就是真正的 HTML 页面。
3、域名(DNS)
在 TCP/IP 协议中使用 IP 地址来标识计算机,数字形式的地址对于计算机来说是方便了,但是对人来说,数字不好记
DNS 就是用有意义名字来代替IP地址那一串数字,就叫做域名
但是我们用 TCP/IP 协议来通信仍然要使用 IP 地址,所以需要把域名做一个转换,“映射”到它的真实 IP,这就是所谓的“域名解析”
域名解析
DNS 的核心系统是一个三层的树状、分布式服务,基本对应域名的结构:
- 根域名服务器(Root DNS Server):管理顶级域名服务器,返回“com”“net”“cn”等顶级域名服务器的 IP 地址;
- 顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如 com 顶级域名服务器可以返回 apple.com 域名服务器的 IP 地址;
- 权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,比如 apple.com 权威域名服务器可以返回 www.apple.com 的 IP 地址。
例如,你要访问“www.apple.com”,就要进行下面的三次查询:
- 访问根域名服务器,它会告诉你“com”顶级域名服务器的地址;
- 访问“com”顶级域名服务器,它再告诉你“apple.com”域名服务器的地址;
- 最后访问“apple.com”域名服务器,就得到了“www.apple.com”的地址。
域名缓存
-
大公司、网络运行商都会建立自己的 DNS 服务器,作为用户 DNS 查询的代理,代替用户访问核心 DNS 系统 用户访问某个网址,并不会直接去请求权威域名服务器,而是请求一些“非权威域名服务器”,由它们代理去请求“权威域名服务器”,如果这些“非权威域名服务器”在自己的缓存中找到了要请求的地址,就直接返回,无需再去请求“权威域名服务器”,大大减轻了“权威域名服务器”的压力。 -
操作系统里也会对 DNS 解析结果做缓存,如果你之前访问过“www.apple.com”,那么下一次在浏览器里再输入这个网址的时候就不会再跑到 DNS 那里去问了,直接在操作系统里就可以拿到 IP 地址。 -
另外,操作系统里还有一个特殊的“主机映射”文件,如果操作系统在缓存里找不到 DNS 记录,就会找这个文件。
4、输入一个URL,会发生什么
4.1、使用 IP 地址访问 Web 服务器
- 浏览器从地址栏的输入中获得服务器的 IP 地址和端口号;
- 浏览器用 TCP 的三次握手与服务器建立连接;
- 浏览器向服务器发送拼好的报文;
- 服务器收到报文后处理请求,同样拼好报文再发给浏览器;浏览器解析报文,渲染输出页面。
4.2、输入一个URL,访问 Web服务器
浏览器首先会判断你输入的是不是 IP 地址,不是的话然后会进行域名解析,然后检查一下浏览器自己的缓存里面有没有,如果没有就向操作系统的缓存要,还没有就检查本机hosts文件我们的本机域名解析文件,如果有就建立 TCP 连接发送 HTTP 请求;
还没有的话,就要从 根域名 顶级域名 权威域名 层层查找
例如,你要访问“www.apple.com”,就要进行下面的三次查询:
- 访问根域名服务器,它会告诉你“com”顶级域名服务器的地址;
- 访问“com”顶级域名服务器,它再告诉你“apple.com”域名服务器的地址;
- 最后访问“apple.com”域名服务器,就得到了“www.apple.com”的地址。
解析失败的浏览器尝试换别的DNS服务器,最终失败的进入错误页面
5、HTTP 报文
HTTP 协议的请求报文和响应报文的结构基本相同,由三大部分组成:
- 起始行(start line):描述请求或响应的基本信息;
- 头部字段集合(header):使用 key-value 形式更详细地说明报文;
- 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。
这其中前两部分起始行和头部字段经常又合称为“请求头”或“响应头”,消息正文又称为“实体”,但与“header”对应,很多时候就直接称为“body”。
HTTP 协议规定报文必须有 header,但可以没有 body
5.1、起始行(请求行、状态行)
请求报文中的起始行叫请求行;
请求行由三部分构成:
- 请求方法:是一个动词,如 GET/POST,表示对资源的操作;
- 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
- 版本号:表示报文使用的 HTTP 协议版本。
响应报文中的起始行叫状态行;
状态行由三部分构成:
- 版本号:表示报文使用的 HTTP 协议版本;
- 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;
- 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。
5.2、头部字段
请求行或状态行再加上头部字段集合就构成了 HTTP 报文里完整的请求头或响应头
头部字段是 key-value 的形式,key 和 value 之间用“:”分隔,最后用 CRLF 换行表示字段结束。比如在“Host: 127.0.0.1”这一行里 key 就是“Host”,value 就是“127.0.0.1”。
6、GET 方法和 POST 方法的区别
- get用来获取数据,post用来提交数据
- get参数有长度限制(受限于url长度,具体的数值取决于浏览器和服务器的限制,最长2048字节),而post无限制。
- get请求的数据会附加在url之 ,以 " ? "分割url和传输数据,多个参数用 "&"连接,而post请求会把请求的数据放在http请求体中。
- get是明文传输,post是放在请求体中,但其实是可以通过抓包工具看到,也相当于是明文的。
get 和 post 本质上其实都是 TCP 连接,因为 HTTP 协议的约定,可能导致了它们在使用的过程中有一点差别,本质上其实是一样的;
**差别就是:**get在请求时发送一个数据包,会将header和data一起发送过去,而post会产生两个数据包先发送header,服务器返回100,然后在发送data,服务器返回200
7、HTTP 响应状态码
状态码的就是表达 HTTP 数据处理的“状态”,客户端可以依据状态码做出下一步的动作
大体分为五类:
- 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
- 2××:成功,报文已经收到并被正确处理;
- 3××:重定向,资源位置发生变动,需要客户端重新发送请求;
- 4××:客户端错误,请求报文有误,服务器无法处理;
- 5××:服务器错误,服务器在处理请求时内部发生了错误。
7.1、2××
2×× 类状态码表示服务器收到并成功处理了客户端的请求
“200 OK”是最常见的成功状态码,表示一切正常
7.2、3××
3×× 类状态码表示客户端请求的资源发生了变动,客户端必须用新的 URI 重新发送请求获取资源,也就是通常所说的“重定向”
“301 Moved Permanently 永久重定向”,含义是此次请求的资源已经不存在了,需要改用新的 URI 再次访问。
“302 Found 临时重定向”,请求的资源还在,但需要暂时用另一个 URI 来访问
7.3、4××
4××类状态码表示客户端发送的请求报文有误,服务器无法处理,它就是真正的“错误码”含义了
“400 Bad Request”是一个通用的错误码,不会指明具体的错误,非常笼统
“403 Forbidden” 表示服务器禁止访问资源。
“404 Not Found” 资源在本服务器上未找到,所以无法提供给客户端。
7.4、5××
5×× 类状态码表示客户端请求报文正确,但服务器在处理时内部发生了错误,无法返回应有的响应数据,是服务器端的“错误码”
“500 Internal Server Error” ,是一个通用的错误码
8、HTTPS
由于 HTTP 是明文传输,整个传输过程完全透明,任何人都能够在链路中截获、修改或者伪造请求 / 响应报文,数据不具有可信性
HTTPS 把 HTTP 的下层协议换成了 SSL/TLS , 让 HTTP 运行在了安全的 SSL/TLS 协议上,相当于是在应用层和传输层之间加了一个TLS安全层
从三个维度来保证 HTTP 的安全:
- 机密性,就是让不该看到的人看不到
- 完整性:保证数据在传输过程中没有被篡改,保持完整性
- 身份认证:确认对方真的是对方,不是别人冒充的
8.1、使用对称和非对称加密结合来保证机密性
对称加密
对称加密就是加密和解密都使用同一个密钥,需要保证密钥的安全,对称加密的问题就在于如何保证密钥的安全传输
非对称加密
非对称加密有两个密钥,一个公钥一个私钥,公钥可以公开随便用,但是私钥必须严格保密
公钥加密只能用私钥解密,私钥加密只能用公钥解密
非对称加密基于大数运算,比如大素数或者椭圆曲线,是复杂的数学难题,所以消耗计算量,运算速度慢。
我们采用非对称加密的方式来传输对称加密的密钥,通过这个方式保证对称加密密钥的安全
8.2、使用摘要算法来保证完整性(数字摘要)
黑客虽然拿不到会话密钥,无法破解密文,但可以通过窃听收集到足够多的密文,再尝试着修改、重组后发给网站。因为没有完整性保证,服务器只能“照单全收”,然后他就可以通过服务器的响应获取进一步的线索,最终就会破解出明文。
摘要算法其实就是哈希算法,就是把一不定长的输入映射成定长的输出;比如说 MD5
我们把对称加密的密钥哈希一下,然后把摘要附在密钥之后,然后用公钥加密进行传输,这个就叫数字摘要
8.3、使用数字证书来解决身份认证
还涉及到一个公钥的信任问题,黑客可以冒充网站发布公钥
这个时候我们需要使用CA来解决公钥信任的问题
小 CA 让大 CA 签名认证,一直到 根CA
证书撤销的问题
|