前面学了一周多的计算机网络,虽然学的还是不太深吧,像什么IP协议中IPV4的划分、计算啊,HTTP2和HTTP3的详细内容啊等等都还是差得蛮多。但是至少懂了局域网、互联网的区别,DNS解析域名,TCP的详细过程以及HTTP/1.1和HTTPS算是还是基本学明白了(至少应付应付前端面试应该没问题吧哈哈哈)。然后趁着最近有空,想自己再回顾回顾这方面的知识,然后写出来怕以后忘了,也希望以后学得更深了,能再回来将这篇内容改造得更好,哈哈~~
OSI网络7层模型与TCP/IP5层模型
| OSI的网络7层模型: | TCP/IP5层模型: | 数据格式: |
|---|---|---|
| 应用层 | 应用层 | |
| 表示层 | 应用层 | |
| 会话层 | 应用层 | |
| 传输层 | 传输层 | 数据段 |
| 网络层 | 网络层 | 分组(数据包) |
| 数据链路层 | 数据链路层 | 帧 |
| 物理层 | 物理层 | 比特流 |
- 物理层就是一般用光纤、同轴电缆连接的,主要就是底层传输比特流(二进制数据),常用的机器有中继器、集线器等。
- 数据链路层常用的就是:交换机、网桥。
- 网络层有路由器。
区别
假如我们要实现两台电脑的通信,我们就可以使用一根光纤连接两台电脑,但是光线的使用距离太短,就得借助中继器:
- 一般光纤的长度过长后(大于几百米),传输效率就会降低。而中继器就是一个机器,连接两根光纤,使效率得到保障!
但是我们有5台电脑需要通信,我们就可以使用集线器:
- 集线器的作用等于中继器,只不过中继器只能连接两根光纤,而集线器可以连很多根。
但是我们又发现集线器不安全:它是广播形式的,我们5台电脑A、B、C、D、E,我们只要A给C发消息,但是集线器会给BCDE都发消息。所以这时就需要交换机:
- 我们每一台设备都有一个网卡,上面有唯一的标识:MAC地址
- 我们的交换机可以存储经过这台交换机的MAC地址,并注明是谁的
- 再当A给C发消息时,就会查找C的MAC地址,直接给C发
这只是形成了一个局域网,如果我们想和外面通信呢?就需要路由器了。
路由器有很多个接口,总的就分为两类:WAN口和LAN口
- WAN的意思是Wide Area Network,表示广泛的网络,将连接外部网络,实现本地和外面通信
- LAN的意思是Locate Area Network,表示本地的网络,类似交换机。
其实如果没有WAN口连接外面的网络,路由器就等于交换机,只能实现局域网。
ipv4
既然我们通过路由器实现了和外面网络的通信,但是外面网络这么大,我们又怎么区分它们谁是谁呢?那就是靠的ip地址。现在大多用的还是ipv4,它是由32位地址组成,分为A、B、C、D、E五类。
ARP地址解析
ARP地址解析其实将ip地址转为MAC地址。ARP是不参与网络层的,我感觉就属于数据链路层。
在交换机中,它是咋存储MAC地址的呢?其实就是使用的ARP协议。当我们事先就知道了目标的ip地址后,我们就可以对其发送ip数据包进行通信了。
- 主机 A 要向某网络设备 X 发送数据时,需要先在其 ARP 高速缓存中查看有无 网络设备X 的 IP 地址。如果有,则直接在 ARP 高速缓存 查出其对应的 物理地址。
- 否则,主机 A 的 ARP 进程在本地局域网发送 ARP 请求广播。如下图。
- 在本地局域网中的所有主机上运行的 ARP 进程 都收到此 ARP 请求。如下图
- 主机 D 的 IP 地址和要查询的网络设备 X 一样,它在收到该 ARP 请求后向主机 A 发送 ARP 响应。
- 主机 A 收到主机 B 的 ARP 响应后, 会在其 ARP 高速缓存中记录 主机B 的 IP 地址到其硬件地址的映射。
注意: ARP 协议是局域网内部的协议。它解决的是同一局域网内部的主机或路由器的 IP 地址和其对应的硬件地址的映射问题。根据 ARP 协议 , 主机 A 无法解析其他网络中的主机的硬件地址。实际上,也不需要主机 A 解析其他网络的主机地址。因为跨网络的数据传输一般是由上层协议来完成的。
DNS
DNS域名解析
IP地址32位,又长又多,我们是记不住那么多ip地址的,所以我们一般使用有意义的字符串来替代ip地址,比如百度:www.baidu.com。但是网络间通信又是通过ip地址来进行查找的,所以在下层,计算机还是得将字符串解析成为ip地址。
首先了解一下DNS与域名,DNS是分布式的维护和解析,基于UDP,53号端口。域名其实是具有一定的层次结构的,从上到下依次为:根域名、顶级域名、二级域名、(三级域名)。
根域名:
www.baidu.com.中最后的.就是根域名顶级域名:就是网址的最后一个部分。比如,网址
www.baidu.com的顶级域名就是.com。ICANN 的一项主要工作,就是规定哪些字符串可以当作顶级域名。截至 2015 年 7 月,顶级域名共有 1058 个,它们大致可以分成两类:
- 一类是通用顶级域名,比如
.com、.net、.edu、.org、.xxx等等,共有 700 多个。- 另一类是国家顶级域名,代表不同的国家和地区,比如
.cn(中国)、.io(英属印度洋领地)、.cc( 科科斯群岛)、.tv(图瓦卢)等,共有 300 多个。而二级域名)在通用顶级域名或国家顶级域名之下具有不同的意义:
- 通用顶级域名下的二级域名:一般是指域名注册人选择使用的网上名称,如
yahoo.com(商业组织通常使用自己的商标、商号或其他商业标志作为自己的网上名称,如baidu.com)- 国家顶级域名下的二级域名:一般是指类似于通用顶级域名的表示注册人类别和功能的标志。例如,在 .com.cn 域名结构中,
.com此时是置于国家顶级域名.cn下的二级域名,表示中国的商业性组织,以此类推。三级域名是形如
www.baidu.com的域名,可以当做是二级域名的子域名,特征为域名包含两个.。对于域名所有者/使用者而言,三级域名都是二级域名的附属物而无需单独费用。三级域名甚至不能称为域名,一般称之为域名下的 “二级目录” 。
1、我们在与其他域名进行通信时,会先在本电脑上的缓存中进行查找,如果找到,就直接返回该域名的ip地址,如果没有找到,就去路由器中找。
- 本地缓存分为两部分内容,浏览器缓存和操作系统缓存。浏览器在获取网站域名的实际 IP 地址后会对其进行缓存,减少网络请求的损耗。每种浏览器都有一个固定的 DNS 缓存时间,如 Chrome 的过期时间是 1 分钟,在这个期限内不会重新请求 DNS。
- 操作系统的缓存其实是用户自己配置的
hosts文件。比如 Windows10 下的hosts文件存放在C:\Windows\System32\drivers\etc\hosts目录中
2、路由器其实也就是本地域名服务器,本地域名服务器会查询自己的 DNS 缓存,查找成功则返回结果(注意:主机和本地域名服务器之间的查询方式是递归查询);
- 在浏览器中进行访问的时候,会优先查询浏览器缓存,如果未命中则继续查询操作系统缓存,最后再查询本地域名服务器,然后本地域名服务器会递归的查找域名记录,最后返回结果。主机和本地域名服务器之间的查询方式是递归查询,也就是说主机请求本地域名服务器,那么本地域名服务器作为请求的接收者一定要给主机想要的答案。
3、如果本地域名服务器没有找到,则本地域名服务器向上级域名服务器进行查询,通过以下方式进行迭代查询(注意:本地域名服务器和其他域名服务器之间的查询方式是迭代查询,防止根域名服务器压力过大):
- 首先本地域名服务器向根域名服务器发起请求,根域名服务器是最高层次的,它并不会直接指明这个域名对应的 IP 地址,而是返回顶级域名服务器的地址,也就是说给本地域名服务器指明一条道路,让他去这里寻找答案
- 本地域名服务器拿到这个顶级域名服务器的地址后,就向其发起请求,获取权限域名服务器的地址
- 本地域名服务器根据权限域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址
4、本地域名服务器将得到的 IP 地址返回给操作系统,同时自己将 IP 地址缓存起来
5、操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来
6、至此,浏览器就得到了域名对应的 IP 地址,并将 IP 地址缓存起来。
所以,DNS解析是迭代递归的,既有迭代,又有递归。
TCP与UDP
UDP
UDP是不可靠的,无连接的。
UDP数据报分为首部和用户数据部分,整个UDP数据报作为IP数据报的数据部分封装在IP数据报中,UDP数据报文结构如图所示:
UDP首部有8个字节,由4个字段构成,每个字段都是两个字节, 1.源端口: 源端口号,需要对方回信时选用,不需要时全部置0. 2.目的端口:目的端口号,在终点交付报文的时候需要用到。 3.长度:UDP的数据报的长度(包括首部和数据)其最小值为8(只有首部) 4.校验和:检测UDP数据报在传输中是否有错,有错则丢弃。 该字段是可选的,当源主机不想计算校验和,则直接令该字段全为0. 当传输层从IP层收到UDP数据报时,就根据首部中的目的端口,把UDP数据报通过相应的端口,上交给应用进程。 如果接收方UDP发现收到的报文中的目的端口号不正确(不存在对应端口号的应用进程0,),就丢弃该报文,并由ICMP发送“端口不可达”差错报文给对方。
TCP
TCP是全双工的、可靠的连接,他需要经过3次握手进行连接,需要进行四次挥手断开连接。
TCP报文
TCP报文段也叫TCP分组,是TCP协议传输和接收数据的一种封装格式,只有按照该格式发送的数据才可以被TCP协议通信的双方正确的接收与解析。
TCP报文的组成部分描述如下:
源端口:标识源端应用进程,即发送TCP分组的进程端口号。 目的端口:标识目的端应用进程,即需要接收分组数据的进程端口号。 序号(seq):在SYN标志未置1时,该字段指示了用户数据区中的第一个字节的序列号;在SYN标志置1时,该字段指示的是初始发送的序列号。 确认号(ACK):用来确认本端TCP实体已经接收到的数据,其值表示期待对端发送的下一个字节的序号,实际上告诉对方,这个序号减1以前的字节已经正确接收。例如发送确认号为1001,则表示前1000个字节已经被确认接收了。 数据偏移:表示以 32bit为单位的TCP分组头的总长度,用于确定用户数据区的起始位置。 RST:连接复位,重新连接 SYN:同步序号,当SYN置1时,表示建立连接,分组将发送seq为初始序列号(其值一般随机) FIN:结束标志,表示关闭连接,当该字段置1时,表示分组将要关闭连接 ACK:确认号有效的标志,置1时表示确认号有效。 URG:紧急指针有效的标志,置1时表示紧急指针有效 PSH:Push操作。
3次握手与4次挥手
3次握手
第一次:客户端随机使用一个未使用的端口向服务器端发送请求,请求连接,SYN,seq = 1;
第二次:服务器端收到请求后,立马回应 ,发送ACK,ack=1,同时它也发送一个请求,请求连接,发送SYN,seq =1;
第三次:客户端收到回复后,回应,发送ACK,ack=1,seq = 2,连接成功。
其实这就是一个建立打电话的过程,因为是全双工的,客户端可以给服务器端发请求,服务器端也可以给客户端发请求:
第一次:A向B打电话,说:我可以以后给你打电话吗?
第二次:B收到电话后,说可以的。(此时只是A可以给B打电话,B还要可以给A打电话)。于是B对A说:我以后可以给你打电话吗?
第三次:A收到B的消息后,说可以呀!然后连接就开始了,A可以给B打,B可以给A打。
为啥不采用2次握手呢?
谢希仁版《计算机网络》中的例子:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
我的理解是除了这个以外,还得向打电话那样,要建立双向的连接就得双方都同意才行。哈哈哈~
为啥不采用4次呢?
只需要3次就可以的事情为啥要4次呢?采用4次会多耗时耗力唉!
4次挥手
挥手与握手类似。
第一次挥手: 客户端因为不再有数据发送给服务器,所以向服务器发送FIN报文表示想要关闭连接,不会再发送数据了。同时包含客户端的报文序号M
第二次挥手: 服务器在接收了来自客户端的FIN报文后,得知客户端不再发送数据,将要关闭连接。但是,此时服务器端获取还有部分数据没有回传给客户端,服务器可能还要向客户端发送一部分数据才能关闭连接。所以服务器不会立马同意关闭连接,而是先发送表示确认信息的ACK报文,该ACK报文中包含了值为M+1的确认号。
第三次挥手: 在服务器端完成向客户端传送最后的数据后,此时不再有数据需要传输了。那么服务器也准备关闭连接,所以向客户端发送表示关闭连接的FIN报文,报文中包含了服务器端的序号N。
第四次挥手: 在客户端也收到了服务器端发送的FIN报文之后,得知服务器端也可以关闭连接了,此时再向服务器发送最后一次确认报文ACK,使连接成功关闭,ACK报文中的确认号为N+1。
为啥是4次不是3次?
因为3次不了啊,握手可以3次是因为可以节省时间,而挥手如果是3次的话(就是将第2和第3次合并),那么服务端还有未发完的数据等待发给客户端时,需要耗时,那客户端一定时间内没有收到回复,它以为它发给客户端的请求丢失了,于是又得重新发请求,请求断开。这就不符合了,所以得收到请求后,立马先回应客户端,让他知道我收到了,然后再将剩余的数据发完,再请求断开。
就像男女朋友分手:
第一次:(男A女B)A向B说:我们分手吧。
第二次:B收到后,很伤心,但是再伤心也得先回复A的分手请求,如果不先回应,A可能就会短信轰炸甚至做出一些不合理的事情出来,
第三次:然后B经过了短暂的自我恢复后,把A送给她的东西全部丢了,然后说:好吧,我们分手吧!
第四次:A收到B的消息后,说:好吧,祝你幸福!
注意:四次挥手后,不是立马断开的,而是客户端得过一段时间后才会断开,为啥?因为第四次挥手时,有可能数据后中途出现故障,或者丢失,那么服务器端就收不到第四次挥手的消息,服务器端就会以为是它的第三次挥手消息客户端没有收到,于是会重发。所以客户端会等待一段时间,如果不再收到服务器端的消息后,才会断开。 这也就是为啥需要第四次挥手的原因。
TCP的滑动窗口
客户端有自己的缓存区,服务端也有自己的缓存区,当在进行通信的时候,会根据网络状况(带宽)调整发送数据的大小。
我们发送数据的时候,发送的数据包是乱序的,当我们接收端收到数据的时候,可能前面的包还没有收到,此时需要等待前面序号的包也收到后,才会滑动这个窗口,允许发送方再进行发送数据包。这也就是TCP的队头阻塞。
TCP在进行通信的时候,发送方发送数据包后,请求放会立刻进行回应。请求方发送数据时,TCP头部会发送PSH代表发送数据,同时会带上seq和ack 和 len。seq代表的是发送的顺序,ack代表的是下次对方应该从哪个顺序开始,len代表发送数据的大小。所以当接收方收到数据后,会检查seq、len和ack的,它就会知道前面还有没有没收到,如果没收到,就等待,收到了就向下滑动通知发送方继续发数据。
超时重传(RTO): 上面挥手已经说了超时重传了,就是那样的。一段时间没有收到回复,就会以为自己发送的数据包丢了,就会重新发送。同时,当接收端的缓存满了后,发送端会一直发一探测包,来询问是否可以调整窗口大小,继续发送数据,如果这时上层协议(HTTP)消耗了接收方的缓存中的数据,接收方就会回复或者主动通知可以继续发数据了。
滑动窗口的作用就是流量控制,控制发送方的频率。
粘包
Nagle算法:任一时刻,只能有一个包在传输中。
这就导致了一个问题,加入我们A向B发送3个数据包,每个数据包的大小都是1字节。但是每次发送的时候,这些数据包都要加上TCP的头部,至少20个字节,也就变成了21字节。那么3个包就成了63个字节,这就会消耗资源。
所以为了解决这个问题,有了一些其他方法---粘包来处理。
比如:Cork算法,当达到MSS(Message Send Size)时,再统一发送数据。(就是帧的大小,-ip头 --tcp头 约1164个字节)
TCP的拥塞窗口(拥塞处理)
假设接收方窗口大小是无限的,接收到数据后就会发送ack,那么传输数据主要是依赖于网络带宽,带宽的大小是有限的。
- TCP维护一个拥塞窗口变量cwnd,在传输过程中没有拥塞就将此值增大。如果出现拥塞(超时重传RTO)就将窗口值减小。
- cwnd < ssthresh 使用曼开始算法
- cwnd > ssthresh 使用拥塞避免算法
- ROT更新时,ssthresh的值变为当前窗口的一半,更新cwnd = 1.
拥塞窗口就像一做桥,桥的两边就是客户端A和服务端B。当我们A向B发数据就类似于A这边的车通过桥去B。如果B那边路很宽,可以停很多车。但是桥的宽度是有限的,我们发10辆车同时过去没问题,但是我们发100辆车同时过去,就芭比Q了,桥堵死了。这就是拥塞了。
我们的解决方案即能避免阻塞又能进来发很多车过去,就是:
- 先发1辆车,,预定32辆车可能出问题,发现没问题
- 再发2辆车,没问题
- 再发4辆车,没问题
- ...
- 再发32辆车,达到预定的值了,但是发现没问题,继续发车
- 再发38辆车,没问题
- 再发44辆车,有问题了
- 重新发一辆车,预定值为22辆车了,
- 重复...
但是这种就效率低,每次拥塞后,就要从1开始从新慢慢的发,效率低。于是就改进了这个算法,有了快重传:
快重传,可能在发送的过程中出现丢包的情况。此时不要立即回退到慢开始阶段,而是对已经收到的报文重复确认,如果确认次数到达3次,则立即进行重传快恢复算法(减少超时重传机制的出现),降低重置cwnd的频率。
HTTP1.1(超文本传输协议)
1999年,广泛使用了HTTP/1.1,官方确定HTTP/1.1 为正式标准,允许持久连接,允许响应数据分块,增加了缓存管理和控制,增加了PUT、DELETE等新的方法。(GET是1990年HTTP/0.9出现的,POST是1996年HTTP/1.0出现的)
HTTP/1.1是基于tcp的,半双工、请求应答模式,是无状态的(每一次请求应答都没有关系,即下一次不知道上一次的内容)。
Http协议由Http请求和Http响应组成,当在浏览器中输入网址访问某个网站时, 你的浏览器会将你的请求封装成一个Http请求发送给服务器站点,服务器接收到请 求后会组织响应数据封装成一个Http响应返回给浏览器。即没有请求就没有响应。
http请求包括:请求行、请求头、请求体
http响应包括:响应行、响应头、响应体
HTTP请求报文
HTTP请求报文由3部分组成(请求行+请求头+请求体):
请求行:
例如:POST /chapter17/user.html HTTP/1.1
格式:请求方式 资源路径 协议/版本
请求行必须在http请求格式的第一行。
get请求:
将请求参数追加在url后面,不安全
url长度限制get请求方式数据的大小
没有请求体
一般的HTTP请求大多都是GET。
post请求:
请求参数在请求体处,较安全。
请求数据大小没有显示
只有表单设置为method=“post”才是post请求,其他都是get请求
常见get请求:地址栏直接访问、<a href="">、<img src="">等
HEAD请求:
HEAD跟GET相似,不过服务端接收到HEAD请求时只返回响应头,不发送响应内容。所以,如果只需要查看某个页面的状态时,用HEAD更高效,因为省去了传输页面内容的时间。
DELETE请求:
删除某一个资源。
OPTIONS请求:
用于获取当前URL所支持的方法。若请求成功,会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET, POST”。
PUT请求:
把一个资源存放在指定的位置上。
本质上来讲, PUT和POST极为相似,都是向服务器发送数据,但它们之间有一个重要区别,PUT通常指定了资源的存放位置,而POST则没有,POST的数据存放位置由服务器自己决定。
TRACE请求:
回显服务器收到的请求,主要用于测试或诊断。
CONNECT请求:
CONNECT方法是HTTP/1.1协议预留的,能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接与非加密的HTTP代理服务器的通信。
HTTP常见请求头:
- Referer:表示这个请求是从哪个url跳过来的,通过百度来搜索淘宝网,那么在进入淘宝网的请求报文中,Referer的值就是:
www.baidu.com。如果是直接访问就不会有这个头。
常用于:防盗链。
Referrer Policy: no-referrer-when-downgrade
- Accept:告诉服务端,该请求所能支持的响应数据类型,专业术语称为MIME 类型(文件类型的一种描述方式)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
MIME格式:大类型/小类型[;参数]
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng, */* ;q=0.8
例如:
text/html,html文件
text/css,css文件
text/javascript,js文件
image/*,所有图片文件
- if-Modified-Sincce:浏览器通知服务器,本地缓存的最后变更时间。与另一个响应头组合控制浏览器页面的缓存
- Cokkie:客户端的Cookie就是通过这个报文头属性传给服务端的哦!
Cookie: JSESSIONID=15982C27F7507C7FDAF0F97161F634B5
- User-Agent:浏览器通知服务器,客户端浏览器与操作系统相关信息.
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
- Connection:表示客户端与服务连接类型;Keep-Alive表示持久连接,close已关闭
Connection: keep-alive
- Host:请求的服务器主机名
Host: sczpkj.f3322.net:3000
- Content-Length:请求体的长度
POST http://39.108.107.149:8080/vk/app/rest/ddp/iModelServiceImpl/findModelByType HTTP/1.1
User-Agent: Fiddler
Host: 39.108.107.149:8080
Content-Length: 11
name=城市
- Content-Type:请求的与实体对应的MIME信息。如果是post请求,会有这个头,默认值为application/x-www-form-urlencoded,表示请求体内容使用url编码
Content-Type: application/x-www-form-urlencoded
- Accept-Encoding:浏览器通知服务器,浏览器支持的数据压缩格式。如GZIP压缩
Accept-Encoding: gzip, deflate
- Accept-Language:浏览器通知服务器,浏览器支持的语言。各国语言(国际化i18n)
Accept-Language: zh-CN,zh;q=0.9
- Cache-Control: 指定请求和响应遵循的缓存机制
对缓存进行控制,如一个请求希望响应返回的内容在客户端要被缓存一年,或不希望被缓存就可以通过这个报文头达到目的。
Cache-Control: no-cache
请求体:
当请求方式是post的时,请求体会有请求的参数,格式如下:
username=zhangsan&password=123
POST http://39.108.107.149:8080/vk/app/rest/ddp/iModelServiceImpl/findModelByType HTTP/1.1
User-Agent: Fiddler
Host: 39.108.107.149:8080
Content-Length: 20
name=城市&status=1
HTTP响应报文
HTTP的响应报文也由三部分组成(响应行+响应头+响应体)
响应行:
①报文协议及版本;
例如:
HTTP/1.1 200 OK
②状态码及状态描述;
状态码:由3位数字组成,第一个数字定义了响应的类别
1xx:指示信息,表示请求已接收,继续处理
2xx:成功,表示请求已被成功接受,处理。
- 200 OK:客户端请求成功
- 204 No Content:无内容。服务器成功处理,但未返回内容。一般用在只是客户端向服务器发送信息,而服务器不用向客户端返回什么信息的情况。不会刷新页面。
- 206 Partial Content:服务器已经完成了部分GET请求(客户端进行了范围请求)。响应报文中包含Content-Range指定范围的实体内容
3xx:重定向
- 301 Moved Permanently:永久重定向,表示请求的资源已经永久的搬到了其他位置。
- 302 Found:临时重定向,表示请求的资源临时搬到了其他位置
- 303 See Other:临时重定向,应使用GET定向获取请求资源。303功能与302一样,区别只是303明确客户端应该使用GET访问
- 307 Temporary Redirect:临时重定向,和302有着相同含义。POST不会变成GET
- 304 Not Modified:表示客户端发送附带条件的请求(GET方法请求报文中的IF…)时,条件不满足。返回304时,不包含任何响应主体。虽然304被划分在3XX,但和重定向一毛钱关系都没有
4xx:客户端错误
- 400 Bad Request:客户端请求有语法错误,服务器无法理解。
- 401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
- 403 Forbidden:服务器收到请求,但是拒绝提供服务
- 404 Not Found:请求资源不存在。比如,输入了错误的url
- 415 Unsupported media type:不支持的媒体类型
- 5xx:服务器端错误,服务器未能实现合法的请求。
500 Internal Server Error:服务器发生不可预期的错误。 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,
响应头:
③响应报文头,也是由多个属性组成;
响应头也是用键值对k:v
服务器通过响应头来控制浏览器的行为,不同的头浏览器操作不同
响应体:
④响应报文体,服务器发送给浏览器的正文,即我们真正要的“干货” ;
响应体,响应体是服务器回写给客户端的页面正文,浏览器将正文加载到内存,然后解析渲染 显示页面内容
内容协商
某一资源,服务器有多个版本,客户端告知服务器自己的偏好,服务器根据偏好选择合适的版本响应客户端的请求。
共有3种不同的方法可以决定服务器上哪个页面最适合客户端:让客户端来选择、服务器自动判定、让中间代理来选。这3种技术分别称为客户端驱动的协商、服务器驱动的协商以及透明协商。
(1)客户端驱动 客户端发起请求,服务器发送可选项列表,客户端作出选择后在发送第二次请求。 优点:比较容易实现; 缺点:增加了时延,至少要发送两次请求,第一次请求获取资源列表,第二次获取选择的副本;
(2)服务器驱动 服务器检查客户端的请求首部集并决定提供哪个版本的页面。 优点:比客户端驱动的协商要快。HTTP提供了q机制,允许服务器近似匹配,还提供了vary首部供服务器告知下游的设备(如代理服务器)如何对请求估值; 缺点:首部集不匹配,服务器要做猜测;
(3)透明协商 某个中间设备(通常是缓存代理)代表客户端进行协商。 优点:免除了web服务器的协商开销,比客户端驱动的协商要快; 缺点:HTTP并没有提供相应的规范;
其中,服务器驱动的解决方案应用的较为广泛。
长连接
HTTP/1.0 是短连接的,就是请求一次返回一次,得先3次握手,接收,返回,4次挥手。每一次请求都要这样,就很耗时。
而HTTP /1.1是长连接的,请求头里的字段Connection: keep-alive就是说的保持连接的意思。这次发送请求回应请求后,连接还是开着的。
管线化(HTTP队头阻塞)
我们针对每个域名分配6个tcp通道,也就是说可以同时开辟6个tcp通道,就是可以一次性发送6个请求(并发)。
但是这还是有问题的:服务器接收到请求后,它会按顺序一个接着一个返回(管道的特点)。
就类似:同时发1、2、3这个请求,服务器收到后,他不管收到的顺序是啥,它就得按1、2、3的顺序返回。所以,这还是没有真正的解决这个并发的问题。
cookie
Cookie通常也叫做网站cookie,浏览器cookie或者httpcookie,是保存在用户浏览器端的,并在发出http请求时会默认携带的一段文本片段。它可以用来做用户认证,服务器校验等通过文本数据可以处理的问题。
Cookie不是软件,所以它不能被携带病毒,不能执行恶意脚本,不能在用户主机上安装恶意软件。但它们可以被间谍软件用来跟踪用户的浏览行为。所以近年来,已经有是欧洲和美国的一些律师以保护用户隐私之名对cookie的种植宣战了。更严重的是,黑客可以通过偷取Cookie获取受害者的帐号控制权。
总结:就是在客户端增加Cookie字段,服务端 set-cookie 每次请求的时候会自动携带cookie
HTTP缓存
分为:强制缓存、协商缓存
强制缓存:
@1:Expires:就是当客户端访问服务器后,服务器说,10s内别来找我了,去你家缓存里找(在这10s内就不会再向服务器发送请求)
但是有个问题:就是客户端和服务器端的时间有可能不一样。
@2:max-age = xxx,放在响应头的cache-control中。缓存的最大时间。
协商缓存:
强制缓存有个缺点,就是当强制缓存时间到后,客户端再向服务器发请求后,服务器需要对比客户端的缓存里的文件和服务端是否一致,如果一致则返回304状态码。如果文件更新了,就采用返回新文件的形式。
在强制缓存发请求得到的状态码仍是200,哪怕没有去服务器。
那如何对比文件有没有修改呢??
当客户端向服务器发送请求时,服务端返回时,会返回一个字段:Last-Modified,文件的最后修改时间,然后下次客户端又发送这个请求时,浏览器会自动带上if/modified-since,来对比文件是否修改,没有就走协商缓存。
问题在于:这个Last-modified只能精确到s,如果1s内改了,它是识别不了的,或者最后修改时间变了,但是内容没有变,这也识别不出来。所以又有了摘要算法。
摘要算法: md5
不同内容的摘要的结果肯定不一样。服务端会对文件做一个签名,然后每次请求客户端都会将缓存中的文件做一份签名发过去,服务器进行比对,如果签名一致,则文件相同。 Etag/if-none-match
文件内容摘要太消耗性能了,所以采用 “弱指纹” 的方式,就是只对文件的长度大小进行签名,而不是对整个内容进行签名。
HTTPS
我们知道HTTP传输的数据是明文传输的,这就会导致一个问题,有些业务需求他不能让其他人看到传输的内容,也就是说,他想对数据进行加密再传输。而目前最安全的就是使用HTTPS来进行数据传输,而HTTPS本质也是HTTP,只是在这之上,它多了一层SSL/TCL,它在将http报文发送给TCP之前,现将其发送给了一个安全层(SSL/TCL),对其进行加密。
对称加密
最开始,大家是使用了对称加密,对称加密就是在服务端有一个密匙——key。客户端如果需要对服务端发送数据,就得先去服务端获取这个密匙——key。然后服务端返回密匙,之后的每一次请求,客户端就会用密匙对数据进行加密,这样数据就不是明文传输,而是加密传输了。
但是这有一个问题,那就是黑客,他也可以去向服务端发请求获取密匙——key,然后再去截取客户端发给服务端的请求,然后用密匙对其进行解密,这样黑客就盗取了我们要发送的数据。所以,这还是不太安全。
非对称加密
既然一个密匙不行,那就用两个密匙吧!
服务端有公钥和私钥
最开始是服务端有两个密匙,一个是公钥,一个是私钥,他们是一对的。当客户端要向服务端发送请求时,就得先去服务端获取公钥,然后服务端返回公钥后,就用公钥对数据进行加密,然后再发送给服务端,服务端收到数据后,就用私钥对其解密,这样就拿到数据了。
由于公钥加密的数据,只能使用私钥进行解密,那么黑客也只能得到公钥,而得不到私钥。所以哪怕黑客截取了数据,也解不出来。但是这又有一个问题了,那就是服务端如果返回的数据也要加密那咋办呢??
服务端和客户端都有公钥和私钥
于是后面就想了一个办法,那就是服务端和客户端都有公钥和私钥。当客户端要向服务端发送请求时,就得先有服务端的公钥,而服务端要返回数据时,就得先有客户端的公钥。所以第一次一般都是客户端发送自己的公钥,去服务端获取服务端的公钥,服务端返回服务端的公钥。之后的每次请求,客户端都会用服务器的公钥对其加密再传输,而服务端收到后就会用自己的私钥解密,然后再用客户端的公钥对返回的数据进行加密,返回给客户端,客户端收到后又用自己的私钥进行解密,拿到客户端的返回数据...
这的确是安全了,但是这又非常耗性能。所以后面又升级了,升级为了 非对称+对称加密结合的方式。
非对称加密 + 对称加密
这个方法只需要客户端有一对公钥和私钥就行了。
当客户端需要传输数据时,会先向服务端索取服务端的公钥,服务端收到后,就会返回自己的公钥。客户端拿到公钥后,就会生成一个随机值,然后用公钥对这个随机值进行加密——形成了KEY,然后发送给服务端,服务端收到后,就会用自己的私钥对其解密,然后得到了这个随机值,然后返回确定。之后,客户端向服务端发送数据时,都会使用KEY进行加密然后再发送,服务端收到后就会使用KEY进行解密。
这样一想,确实是安全啊,你黑客哪怕拿到了他们之间的数据也没用,你没有KEY对其进行解密。
但是,黑客中也有高手啊,居然想出了——中间代理人的方法。那就是他截取到了客户端向服务端索取公钥的请求,然后它就给客户端返回一个自己的公钥,然后再向服务端索要服务端的公钥。之后客户端将加密后的随机值发送过去,其实就是发送给了黑客这个代理人,他收到后就用自己的私钥进行解密,然后拿到了这个随机值,再给客户端返回确认,之后,它在用服务端的公钥对这个随机值(或者其他值)进行加密,发送给服务端,服务端收到后,就会用自己的私钥对其解密,就拿到了黑客发给它的随机值,然后返回确认。这样,以后每次客户端发送给服务端的数据,黑客都可以用客户端的随机值进行解密,在用自己的随机值进行加密发送给服务端,再截取到服务端返回的数据后,再用自己的随机值解密,解密后又用客户端的随机值加密发送给客户端,这样,数据就泄露啦!
数字认证
我们想想,发现上面的非对称+对称之所以失败,无非就是因为客户端无法识别这返回的信息是不是我要的服务端返回的。也就是无法认证是谁返回了消息。于是这就有了数字认证CA。
数字认证是一个公司在管,这个公司有属于自己的公钥和私钥,它的公钥保存在任何一台电脑的操作系统中,私钥就只保存在自己那里,谁也不给。
服务端也有自己的公钥和私钥。
认证就是:服务端将自己的公钥和自己的信息发给CA,CA就会用自己的私钥对这些信息进行加密,然后返回给服务端。这样服务端就多了一个数据,CA返回的信息——我们就叫他证书。
以后客户端向服务端请求时,服务端返回的就不是它自己的公钥啦,而是自己的证书。客户端拿到证书后,就会去操作系统里用公钥对其解密,拿到服务端的信息和服务端的公钥,然后确认完毕后,发现是自己要请求的服务端,就会生成随机值,然后用公钥加密发给服务端,服务端在用私钥对其解密拿到随机值,这样以后就可以使用随机值进行对称加密啦。
详细的HTTPS通信步骤(TLS四次握手)
我们上面数字认证谈的只是HTTPS的大概原理,其实真正的步骤比这个要复杂一些(就是多了几个步骤而已)
第一次握手:
四次握手的第一次握手是客户端向服务器发送Client Hello消息,消息以明文的形式传输,里面包括客户端支持的协议版本、加密套件、压缩算法、客户端生成的一个随机数R1、扩展字段等。其中加密套件是四个功能的组合,即:认证算法(Au)、密钥交换算法(KeyExchange)、对称加密算法(Enc)和信息摘要算法,随机数R1则会在后面的密钥生成中使用到。
第二次握手:
① 应对客户端发来的Client Hello,服务器将发送Server Hello消息进行响应,该消息以明文的形式传输,相应消息包括确认使用的协议版本、由服务器生成的随机数R2,确认使用的加密套件、确认使用的压缩方法。
② 在发完Server Hello消息后,服务器会马上将自己的Certificate(公钥证书)发送给客户端。
③ Server Key Exchange并非必需选项,只有在选用了DH算法的情况下,服务器需要将DH参数发送给客户端,若选择了RSA算法则不需要发送Server Key Exchange。
④ Certificate Request也并非必须选项,在对于安全性要求较高的场景中,服务器可要对客户端的身份进行认证,因此发起了对客户端公钥证书的请求,一般情况下浏览器都会内置一对独一无二的公私钥。
⑤ 由于第二次握手中包含一些可选选项,因此需要服务器发送一个Server Hello Done的消息,用来通知客户端Server Hello过程结束。
在客户端收到Server Hello Done之后并没有马上进行第三次握手,而是先对服务器传来的证书进行验证,一般会验证证书是否在有效期内,随后根据CRL或者OCSP查询证书是否有效,最后根据证书链从根CA开始验证直到网站证书,以确保证书的真实性。在这个过程中若出现了验证不通过的结果,则抛出相应的错误;若验证通过,就再生成一个随机数Pre-master,并用服务器公钥进行加密,生成PreMaster Key。
第三次握手:
① Client Key Exchange就是客户端将PreMaster Key发送给服务器,服务器则会用自己的私钥解密得出Pre-master。到这里客户端和服务器都拥有了三个随机数R1、R2和Pre-master,两边再用相同的算法和这三个随机数生成一个密钥,用于握手结束后传输数据的对称加密。
② Change Cipher Spec是客户端向服务器通知,后面发送的消息都会使用协商出来的密钥进行加密。
③ Encrypted Handshake Message是客户端向服务发送握手数据加密信息,该信息是客户端将前面的握手消息利用协商好的摘要算法生成摘要,再用协商好的密钥对摘要进行加密而的出来的,最后将加密信息发送给服务器,这是客户端发出的第一条加密信息。而服务器也会用协商好的密钥进行解密,若能成功解密则说明协商出来的密钥是一致的。
④ Certificate是在第二次握手的第4步有进行的情况下,即服务器有向客户端请求证书的情况才会有的,这一步是客户端向服务器发送客户端的证书,而服务器收到证书后也会对证书进行相同的验证。
第四次握手:
① Change Cipher Spec是服务器向客户端通知,后面发送的消息都会使用协商出来的密钥进行加密。
② Encrypted Handshake Message与第三次握手类似,是服务器发给客户端的用来确定协商的密钥是一致的,也是一条Server Finish消息。
至此TLS四次握手也就完成了,双方已经协商好使用的加密套件和对称密钥,接下来的交互数据都将经过加密后再使用TCP进行传输。
HTTP2
首先为啥要出现HTTP2?
其实就是因为HTTP/1.1 还是有很多问题的。
HTTP/1.1 的问题:
1、TCP 连接数限制:对于同一个域名,浏览器最多只能同时创建 6~8 个 TCP 连接 (不同浏览器不一样)。
2、线头阻塞:每个 TCP 连接同时只能处理一个请求 - 响应,浏览器按 FIFO 原则处理请求,如果上一个响应没返回,后续请求 - 响应都会受阻。为了解决此问题,出现了 管线化 技术,但是管线化存在诸多问题,比如第一个响应慢还是会阻塞后续响应、服务器为了按序返回相应需要缓存多个响应占用更多资源、浏览器中途断连重试服务器可能得重新处理多个请求、还有必须客户端 - 代理 - 服务器都支持管线化
3、Header 内容多,而且每次请求 Header 不会变化太多,没有相应的压缩传输优化方案
4、为了尽可能减少请求数,需要做合并文件、雪碧图、资源内联等优化工作,但是这无疑造成了单个请求内容变大延迟变高的问题,且内嵌的资源不能有效地使用缓存机制
5、明文传输不安全
HTTP2的优点:
1、二进制分帧层 (Binary Framing Layer)
帧是数据传输的最小单位,以二进制传输代替原本的明文传输,原本的报文消息被划分为更小的数据帧。
2、多路复用 (MultiPlexing)
在一个 TCP 连接上,我们可以向对方不断发送帧,每帧的 stream identifier 的标明这一帧属于哪个流,然后在对方接收时,根据 stream identifier 拼接每个流的所有帧组成一整块数据。 把 HTTP/1.1 每个请求都当作一个流,那么多个请求变成多个流,请求响应数据分成多个帧,不同流中的帧交错地发送给对方,这就是 HTTP/2 中的多路复用。
流的概念实现了单连接上多请求 - 响应并行,解决了线头阻塞的问题,减少了 TCP 连接数量和 TCP 连接慢启动造成的问题
所以 http2 对于同一域名只需要创建一个连接,而不是像 http/1.1 那样创建 6~8 个连接。
3、服务端推送 (Server Push)
浏览器发送一个请求,服务器主动向浏览器推送与这个请求相关的资源,这样浏览器就不用发起后续请求。
Server-Push 主要是针对资源内联做出的优化,相较于 http/1.1 资源内联的优势:
- 客户端可以缓存推送的资源
- 客户端可以拒收推送过来的资源
- 推送资源可以由不同页面共享
- 服务器可以按照优先级推送资源
4、Header 压缩 (HPACK)
使用HPACK算法来压缩首部内容
5、应用层的重置连接
对于 HTTP/1 来说,是通过设置 tcp segment 里的 reset flag 来通知对端关闭连接的。这种方式会直接断开连接,下次再发请求就必须重新建立连接。HTTP/2 引入 RST_STREAM 类型的 frame,可以在不断开连接的前提下取消某个 request 的 stream,表现更好。
6、请求优先级设置
HTTP/2 里的每个 stream 都可以设置依赖 (Dependency) 和权重,可以按依赖树分配优先级,解决了关键请求被阻塞的问题
7、流量控制
每个 http2 流都拥有自己的公示的流量窗口,它可以限制另一端发送数据。对于每个流来说,两端都必须告诉对方自己还有足够的空间来处理新的数据,而在该窗口被扩大前,另一端只被允许发送这么多数据。
8、HTTP/1 的几种优化可以弃用
合并文件、内联资源、雪碧图、域名分片对于 HTTP/2 来说是不必要的,使用 h2 尽可能将资源细粒化,文件分解地尽可能散,不用担心请求数多
HTTP3
2018年HTTP3发布,基于UDP的QUIC协议。(HTTP2我都还没搞太懂,算是把HTTP1.1和HTTPS懂了一些了,这些就有空再专研专研吧)
参考资料:
《计算机网络》
珠峰教育
RAP:blog.csdn.net/yanglingwel…
DNS:blog.csdn.net/qq_35246620…
TCP:blog.csdn.net/weixin_4586…
http:blog.csdn.net/weixin_3808…
TLS四次握手:blog.csdn.net/weixin_4404…