文章目录
- 1. TCP/IP网络模型有哪几层并做简要介绍?
- 2. 键入网址到网页显示,期间发生了什么?
- 3. 介绍一下域名解析的工作流程?
- 4. MAC发送方和接收方如何确认?
- 5. 路由器和交换机的区别?
- 6. Linux系统是如何收发网络包的?
- 7. HTTP是什么?
- 8. HTTP常见的状态码有哪些?
- 9. HTTP 常见字段有哪些?
- 10. GET和POST有什么区别?
- 11. HTTP 缓存有哪些实现方式?
- 12. 什么是强制缓存?
- 13. 什么是协商缓存?
- 14. 使用ETag字段实现的协商缓存的过程是怎样的?
- 15. HTTP/1.1的优点有哪些?
- 16. HTTP/1.1的缺点有哪些?
- 17. HTTP/1.1的性能如何?
- 18. HTTP与HTTPS有哪些区别?
- 19. HTTPS解决了HTTP的哪些问题?如何解决的?
- 20. HTTPS是如何建立连接的?期间交互了什么?
- 21. 客户端校验数字证书的流程是怎样的?
- 22. HTTPS的应用数据是如何保证完整性的?
- 23. HTTPS一定安全可靠吗?数据会被假基站转发到中间人服务器,然后客户端与中间人服务器进行通信,中间人服务器再与真正的服务器进行通信吗?
- 24. 为什么抓包工具能截取 HTTPS 数据?
- 25. 如何避免被中间人抓取数据?
- 26. HTTP/1.1 相比 HTTP/1.0 提高了什么性能?
- 27. HTTP/1.1 的性能瓶颈有哪些?
- 28. HTTP/2 做了什么优化?
- 29. HTTP/2 有什么缺陷?
- 30. HTTP/3 做了哪些优化?
- 31. HTTP/1.1 该如何优化?
- 32. 如何避免发送 HTTP 请求?
- 33. 如何减少 HTTP 请求次数?
- 34. 如何减少 HTTP 响应的数据大小?
- 35. RSA算法的缺陷
- 36. RSA 和 ECDHE 握手过程的区别
- 37. 既然有RPC了, 为什么还要有HTTP呢?
- 38. HTTP和RPC有什么区别?
- 39. 既然有HTTP协议,为什么还要有WebSocket?
- 40. 怎么建立WebSocket连接?
TCP/IP网络模型总共分为四层,从上到下分别为应用层、传输层、网络层以及网络接口层。
应用层:只需要专注于为用户提供应用功能,比如HTTP、FTP、DNS、SMTP等;
传输层:为应用层提供网络支持。在传输层有两个传输协议,分别是TCP和UDP。传输层的报文中会携带端口号,因此接收方可以识别出该报文是发给哪个应用。
网络层:网络层主要负责网络包的分片、路由以及转发功能,将数据从一个设备传输到另一个设备。网络层最常使用的是IP协议,如果IP报文大小超过MTU就会对其分片。
网络接口层:在IP头部的前面加上MAC头部,并封装成数据帧发送到网络中,主要为网络层提供链路级别传输的服务,负责在以太网、WIFI这样的底层网络上发送原始数据包,工作在网卡这个层次,使用MAC地址来标识网络上的设备。
域名解析的工作流程如下:
发送方的MAC地址是在网卡生产时写入到ROM里的,只要将这个值读取出来写入到MAC头部就可以了。
在确认接收方的MAC地址时,首先需要在路由表中查询到接收方的IP地址。然后通过ARP协议找到路由器的MAC地址。
ARP协议会在以太网中以广播的形式发送IP地址,询问接收方对应的MAC地址,接收方收到后,会和自己的IP地址进行比对,接着把自己的MAC地址返回给发送方,由此也得到了接收方的MAC地址。操作系统会把本次查询结果放在ARP缓存中,缓存时间就几分钟。通过arp -a命令来查看ARP缓存的内容。
因为路由器是基于 IP 设计的,俗称三层网络设备,路由器的各个端口都具有 MAC 地址和 IP 地址;而交换机是基于以太网设计的,俗称二层网络设备,交换机的端口不具有 MAC 地址。
Linux接收网络包的流程:
当网卡接收到一个网络包后,会通过DMA技术将网络包写入到指定的内存地址,也就是写入到Ring Buffer环形缓冲区,接着网卡向CPU发起硬件中断,当CPU收到硬件中断请求后,根据中断表,调用已经注册的硬件中断处理函数。硬件中断处理函数首先暂时屏蔽中断,表示已经知道内存中有数据了,告诉网卡下次再收到数据包直接写内存就可以了,这样可以提高效率,避免CPU不停的被中断。接着,发起软中断,然后恢复刚才屏蔽的中断。当ksoftirqd内核线程收到软中断后,就会来轮询处理数据,从Ring Buffer中获取一个数据帧,用sk_buff表示,从而可以作为一个网络包交给网络协议进行逐层处理。
Linux 发送网络包的流程:
首先,应用程序会调用 Socket 发送数据包的接口,由于这个是系统调用,所以会从用户态陷入到内核态中的 Socket 层,内核会申请一个内核态的 sk_buff 内存,将用户待发送的数据拷贝到 sk_buff 内存,并将其加入到发送缓冲区。接下来,网络协议栈从 Socket 发送缓冲区中取出 sk_buff,并按照 TCP/IP 协议栈从上到下逐层处理。如果使用的是 TCP 传输协议发送数据,那么先拷贝一个新的 sk_buff 副本 ,接着,对 sk_buff 填充 TCP 头。然后交给网络层,在网络层里会做这些工作:选取路由(确认下一跳的 IP)、填充 IP 头、netfilter 过滤、对超过 MTU 大小的数据包进行分片。处理完这些工作后会交给网络接口层处理。网络接口层会通过 ARP 协议获得下一跳的 MAC 地址,然后对 sk_buff 填充帧头和帧尾,接着将 sk_buff 放到网卡的发送队列中。这一些工作准备好后,会触发「软中断」告诉网卡驱动程序,这里有新的网络包需要发送,驱动程序会从发送队列中读取 sk_buff,将这个 sk_buff 挂到 RingBuffer 中,接着将 sk_buff 数据映射到网卡可访问的内存 DMA 区域,最后触发真实的发送。当数据发送完成以后,其实工作并没有结束,因为内存还没有清理。当发送完成的时候,网卡设备会触发一个硬中断来释放内存,主要是释放 sk_buff 内存和清理 RingBuffer 内存。最后,当收到这个 TCP 报文的 ACK 应答时,传输层就会释放原始的 sk_buff 。
HTTP是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
1xx 类状态码属于提示信息,是协议处理中的一种中间状态。2xx 类状态码表示服务器成功处理了客户端的请求。
200 OK是最常见的成功状态码,表示一切正常。204 No Content也是常见的成功状态码,其中响应头没有body数据。206 Partial Content表示响应返回的body数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。3xx 类状态码表示客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
301 Moved Permanently表示永久重定向,需改用新的 URL 再次访问。302 Found表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。304 Not Modified表示资源未修改,缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
400 Bad Request表示客户端请求的报文有错误,但只是个笼统的错误。403 Forbidden表示服务器禁止访问资源,并不是客户端的请求出错。404 Not Found表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
500 Internal Server Error是个笼统通用的错误码,服务器发生了错误。501 Not Implemented表示客户端请求的功能还不支持。502 Bad Gateway通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。503 Service Unavailable表示服务器当前很忙,暂时无法响应客户端。Host字段:客户端发送请求时,用来指定服务器的域名。Connection字段:常用于客户端要求服务器使用HTTP 长连接机制,需要指定Connection首部字段的值为Keep-Alive。Content-Length字段:服务器在返回数据时,会有Content-Length字段,表明本次回应的数据长度。Content-Type字段:用于服务器回应时,告诉客户端本次传输的数据格式。Accept字段:客户端请求的时候,可以使用Accept字段声明自己可以接受的数据格式。Content-Encoding字段:Content-Encoding字段说明数据的压缩方法,表示服务器返回的数据使用的压缩格式。Accept-Encoding字段:客户端在请求时,用Accept-Encoding字段说明自己可以接受的压缩方法。HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存。
强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动权在于浏览器这边。
强缓存是利用两个 HTTP 响应头部(Response Header)字段Cache-Control和Expires实现的,它们都用来表示资源在客户端缓存的有效期。Cache-Control 的优先级高于 Expires,所以建议使用Cache-Control来实现强缓存。
强缓存的具体实现流程:
Cache-Control,Cache-Control 中设置了过期时间大小;Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;Cache-Control。协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存。
协商缓存可以基于两种头部来实现。第一种是基于请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现;第二种是基于请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段。
协商缓存这两个字段都需要配合强制缓存中Cache-Control字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
当使用 ETag 字段实现的协商缓存的过程:
ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;If-None-Match 字段,该字段的值就是 ETag 唯一标识;If-None-Match 值与当前请求的资源生成的唯一标识进行比较:
304 Not Modified,不会返回资源;200 状态码和返回资源,并在响应头部加上新的 ETag 唯一标识;304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源。HTTP1.1最突出的优点是简单、灵活和易于扩展、应用广泛和跨平台。
header + body,头部信息也是key-value简单文本格式,易于理解。HTTP协议有优缺点一体的双刃剑,分别为无状态、明文传输,同时还有一大缺点不安全。
Cookie技术,在客户端第一次请求后,服务器返回的响应报文中携带一个装有客户信息的Cookie,后续客户端再次请求服务器时,在请求报文中带上Cookie,服务器检查Cookie即可。HTTP协议是基于TCP/IP,并且使用了请求-应答的通信模式,所以性能的关键也在这两点上。
HTTP是超文本传输协议,信息是明文传输,存在安全风险的问题;HTTPS则解决HTTP不安全的缺陷,在TCP和HTTP网络层之间加入了SSL/TLS安全协议,使得报文能够加密传输。HTTP连接建立相对简单,TCP三次握手之后便可进行HTTP的报文传输。而HTTPS在TCP三次握手之后,还需进行SSL/TLS的四次握手过程,才可进入加密报文传输。HTTP默认端口号是80,HTTPS默认端口号是443。HTTPS协议需要向CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。HTTP 由于是明文传输,所以安全上存在以下三个风险:窃听风险,篡改风险,冒充风险。
HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议,可以很好的解决了上述的风险:
HTTPS采取的解决办法:


HTTPS建立连接的过程中,首先需要经过TCP三次握手连接,接着是TLS四次握手阶段,使用不同的密钥交换算法,TLS握手流程也会不一样的,现在常用的密钥交换算法有RSA算法和ECDHE算法。
基于RSA算法的TLS握手过程如下图:

TLS协议建立的详细流程:
ClientHello请求。Client Random),后面用于生成会话秘钥条件之一。Server Random),也是后面用于生产会话秘钥条件之一。RSA 加密算法。pre-master key)。该随机数会被服务器公钥加密。Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的会话秘钥。pre-master key)之后,通过协商的加密算法,计算出本次通信的会话秘钥。
CA 签发证书的过程,如上图左边部分:
客户端校验服务端的数字证书的过程,如上图右边部分:
但事实上,证书的验证过程中还存在一个证书信任链的问题,因为我们向CA申请的证书一般不是根证书签发的,而是由中间证书签发的。证书的验证过程是从根证书信任中间证书,然后中间证书信任服务器的证书,一层层的验证就构成了一条信任链路。
使用证书链的目的是为了确保根证书的绝对安全性,将根证书隔离地越严格越好,不然根证书如果失守了,那么整个信任链都会有问题。
TLS 在实现上分为握手协议和记录协议两层:
TLS 记录协议主要负责消息(HTTP 数据)的压缩,加密及数据的认证。具体过程如下:
从客户端的角度看,其实并不知道网络中存在中间人服务器这个角色。那么中间人就可以解开浏览器发起的 HTTPS 请求里的数据,也可以解开服务端响应给浏览器的 HTTPS 响应数据。相当于,中间人能够窃听了浏览器与服务端之间的 HTTPS 请求和响应的数据。
但是要发生这种场景是有前提的,前提是用户点击接受了中间人服务器的证书。
HTTPS 协议本身到目前为止还是没有任何漏洞的,即使你成功进行中间人攻击,本质上是利用了客户端的漏洞(用户点击继续访问或者被恶意导入伪造的根证书),并不是 HTTPS 不够安全。
很多抓包工具 之所以可以明文看到 HTTPS 数据,工作原理与中间人一致的。
使用抓包工具进行 HTTPS 抓包的时候,需要在客户端安装 Fiddler 的根证书,这里实际上起认证中心(CA)的作用。
抓包工具能够抓包的关键是客户端会往系统受信任的根证书列表中导入抓包工具生成的证书,而这个证书会被浏览器信任,也就是抓包工具给自己创建了一个认证中心 CA,客户端拿着中间人签发的证书去中间人自己的 CA 去认证,当然认为这个证书是有效的。
通过 HTTPS 双向认证来避免被中间人抓取数据。
如果用了双向认证方式,不仅客户端会验证服务端的身份,而且服务端也会验证客户端的身份。服务端一旦验证到请求自己的客户端为不可信任的,服务端就拒绝继续通信,客户端如果发现服务端为不可信任的,那么也中止通信。
HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。
那 HTTP/2 相比 HTTP/1.1 性能上的改进:
HPACK算法,在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。Stream 的概念,1 个 TCP 连接包含多个 Stream,Stream 里可以包含 1 个或多个 Message,Message 对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成。HTTP/2 通过 Stream 的并发能力,解决了 HTTP/1 队头阻塞的问题,但是HTTP/2 还是存在“队头阻塞”的问题,只不过问题不是在 HTTP 这一层面,而是在 TCP 这一层。
HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当前 1 个字节数据没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。
一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。
HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!
HTTP3通过基于UDP的QUIC协议实现了类似TCP的可靠性传输。
QUIC 有以下 3 个特点:无队头阻塞、更快的连接建立、连接迁移。
避免发送 HTTP 请求的方法就是通过缓存技术,客户端会把第一次请求以及响应的数据保存在本地磁盘上,其中将请求的 URL 作为 key,而响应作为 value,两者形成映射关系。
如果客户端的缓存没有过期或者服务器的Etag摘要未发生改变,则说明缓存是可以继续使用的,那么服务器仅返回不含有包体的 304 Not Modified 响应,告诉客户端仍然有效,这样就可以减少响应资源在网络中传输的延时。
可以从3个方面来减少HTTP请求次数:减少重定向请求次数、合并请求、延迟发送请求。
我们可以考虑对响应的资源进行压缩,这样就可以减少响应的数据大小,从而提高网络传输的效率。
使用RSA密钥协商算法的最大问题是不支持前向保密。
因为客户端传递随机数(用于生成对称加密密钥的条件之一)给服务端时使用的是公钥加密的,服务端收到后,会用私钥解密得到随机数。所以一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。
Server Key Exchange消息,而 RSA 握手过程没有该消息。纯裸 TCP 是能收发数据,但它是个无边界的数据流,上层需要定义消息格式用于定义消息边界。于是就有了各种协议,HTTP 和各类 RPC 协议就是在 TCP 之上定义的应用层协议。
HTTP 主要用于 B/S 架构,而 RPC 更多用于 C/S 架构。但现在其实已经没分那么清了,B/S 和 C/S 在慢慢融合。很多软件同时支持多端,所以对外一般用 HTTP 协议,而内部集群的微服务之间则采用 RPC 协议进行通讯。
Header是用于标记一些特殊信息,其中最重要的是消息体长度。Body则是真正传输的内容,而这些内容只能是二进制01串,计算机只认识二进制代码。所以TCP传输字符串和数字问题不大,因为字符串可以转成编码再变成 01 串,而数字本身也能直接转为二进制。但结构体需要通过Json或者Protobuf等技术将它也转为二进制 01 串。对于主流的 HTTP/1.1,它传的内容以字符串为主,Header 和 Body 都是如此。在 Body 这块,它使用 Json 来序列化结构体数据。以key-value的方式存储数据,内容非常多的冗余,传输效率不高。
而RPC采用Protobuf或者其他序列化协议去保存结构体数据,同时也不需要像HTTP那样考虑各种浏览器行为,比如302重定向等。因此,RPC相比于HTTP/1.1性能更好一些,这也是在公司内部微服务中抛弃HTTP,选择使用RPC的最主要原因。
浏览器在 TCP 三次握手建立连接之后,都统一使用 HTTP 协议先进行一次通信。
HTTP 请求,那后续双方就继续用普通 HTTP 协议进行交互。WebSocket 连接,就会在 HTTP 请求里带上一些特殊的 header 头,如下:Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
Connection: Upgrade),并且想升级成 WebSocket 协议(Upgrade: WebSocket)。同时带上一段随机生成的 base64 码(Sec-WebSocket-Key),发给服务器。Sec-WebSocket-Accept 头里,同时带上101状态码(表示协议切换),发回给浏览器。HTTP 的响应如下:HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n
Upgrade: WebSocket\r\n
Connection: Upgrade\r\n