本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com
前言最近面试,总有不同的公司问我有关 http 的问题,虽然说或多或少都能答上来一些,但看着面试官淡漠的眼神就知道这题完蛋🥲。所以这两天也搜罗了一些文章或是视频来补充自己对这方面的理解。在这写成一篇笔记吧,以便记忆以及总结巩固。
一、DNS 解析
当我们在搜索框手动输入 www.baidu.com[1] 时,浏览器到底是做了什么呢?首先就是 DNS 解析。
DNS 解析是一个分布式数据库系统,为了将域名,例如 baidu.com,转换为对应的 IP 地址。
前面的 www 就是一个约定俗成的习惯,用于指代网站的主服务器,通常被用作一个域名的一部分,这里不需要过多关注。
那么为什么需要域名呢?其实完全只是为了好记罢了,毕竟作为一个这么有排面的公司,无论是从知名度还是简便性考虑,这都比一串 ip 地址要很得多。
DNS 解析的过程是这样的。
到本地域名服务器,一般是互联网服务提供商提供的,查找域名对应的 ip
找不到,就到根域名服务器查找域名对应的 ip
再找不到,就到顶级域名服务器查找域名对应的 ip
还找不到,就到目标域名服务器查找域名对应的 ip
找到后,将 ip 写入 DNS 缓存,方便下次直接在本地查找的到这个域名对应的 ip
这样才是和我们直接输入 ip 地址是一样的。只要将上面的图示理解清楚,那对应的 DNS 解析的题也就手到擒来。
二、建立连接
客户端需要和服务端先建立连接,就要提到 TCP 协议了。三次握手,大家应该都很清楚了,这也是我第一次被问到的这类问题,我回忆起来,答的应该还行。
1. 三次握手
客户端向服务端发送建立连接请求,客户端进入 SYN-SENT 状态
服务端向客户端发送同意连接的应答,服务端进入 SYN-RECEIVED 状态
客户端接收到服务端的同意应答后,再向服务端发送一个确认收到的应答,客户端进入 ESTABLISHED 状态,服务端也进入 ESTABLISHED 状态
为什么一定要三次握手,两次行不行?
有一种情况,客户端向服务端发送第一个连接请求 A,但是 A 因为某种非人为原因到达不了服务端,此时因为 TCP 协议内定的超时重传机制,客户端将会再一次发送请求,这里称为 B。后面一切正常,客户端也接收到了服务端发来的数据,然后自然而然的关闭连接。这时候丢失的连接请求 A 又到达了服务端,服务端也就处于连接状态,等待客户端的数据请求,但是此时客户端并不知道之前发送的连接请求到达了服务端,所以始终处于关闭连接状态,这样服务端就会一直处于等待状态,浪费性能。
所以第一次的握手就是让服务端明白自己拥有接收请求的能力,然后服务端发送第二次握手,如果客户端成功接收到后,就明白自己能够发送请求,毕竟自己都接收到了对方的答复,也代表能接收请求。但是这样服务端并不知道自己的第二次握手对方有没有接收到,所以客户端需要发送第三次握手,等到服务端成功接收到后,就代表双方都拥有发送和接收请求的能力。
2. 数据传输
做完连接,就可以开始正式的 HTTP 数据传输了。其实要说的话,建立连接的时候也就可以传输数据了,只是很小而已。
数据传输用到的是 HTTP 协议,TCP 协议是专门用来建立连接用的。下面就介绍一下 HTTP 的历史版本,里面也有一些常考的题。
HTTP 0.9
HTTP 协议是超文本传输协议,一开始被打造是用来实验室传输 html 文本。
请求行采用 GET 方法,后跟一个空格,接着是资源的路径。GET /index.html
传输的 HTML 文件是以 ASCII 编码的纯文本文件,不支持二进制数据传输。
HTTP 1.0
0.9 的问题:多种类型的资源文件需要被传输。
所以增加 请求头、响应头 -- 实现客户端和服务端的交流。
请求头:
accept: text/html 表示客户端可以接受 HTML 格式的文档。
accept-encoding: gzip,deflate,br 表示客户端支持的数据压缩格式。
accept-Charset: utf-8 表示客户端优先接受 UTF-8 字符集的数据。
accept-language: zh-CN,zh;q=0.9,en;q=0.8,pt;q=0.7 表示客户端首选的语言和地区。
响应头:
content-encoding: br
content-type: text/html;charset=utf
HTTP 状态码用于表示服务器响应的状态。常见的状态码有这些:
2xx 成功:
200 OK:请求已成功,响应中包含所请求的信息。
201 Created:请求已成功创建资源。
204 No Content:服务器已经成功处理了请求,但没有返回任何内容。
3xx 重定向:
301 Moved Permanently:请求的资源已被永久移动到新位置。
302 Found:请求的资源临时位于另一个 URI。
304 Not Modified:客户端请求的资源尚未更改,使用缓存版本即可。
4xx 客户端错误:
400 Bad Request:请求语法错误。
401 Unauthorized:请求要求用户的身份认证。
403 Forbidden:服务器理解请求客户端的请求,但是拒绝执行此请求。
404 Not Found:请求的资源不存在。
5xx 服务器错误:
500 Internal Server Error:服务器遇到未知的错误。
502 Bad Gateway:作为网关或代理工作的服务器,从上游服务器收到了无效响应。
503 Service Unavailable:服务器目前无法使用(由于超载或停机维护)。
这样的一些状态码只有多记了,一般的话一些常见的报错看多了也就自然而然的记住了。
HTTP 1.1
1.0 的问题:HTTP 的短连接。
1.1 建立了长连接,也叫持久连接。在 1.0 版本中,每次客户端向服务端请求数据都需要经历三次挥手、发送请求、接收响应、四次挥手这几个步骤,也不是说这些步骤不重要,只是当浏览器先请求 html,接着又需要 css,这样一次次的建立连接,断开连接是很浪费时间的。
虽然允许同时建立最多六个 TCP 连接,每个连接又可以有多个 http 请求,但是并不能同时发送请求,而是需要等待上一次的请求和响应都到位后,接着才可以发送下一次的请求。这也被称为 http 队头阻塞,也几乎是这方面必考的题。
在 1.0 的版本中还允许对虚拟机的支持。每台物理设备都有对应的 ip,但是虚拟机呢?是也有对应的 ip 吗?看个例子吧。
假设有一台物理服务器,IP 地址为 192.168.1.100,并设置了桥接模式的虚拟机网络配置:
虚拟机 A:
IP 地址:
192.168.1.100域名:
example.com
虚拟机 B:
IP 地址:
192.168.1.100域名:
anotherexample.com
访问过程
1. 用户访问:
用户在浏览器中输入
example.com。浏览器向 DNS 服务器发送请求,解析
example.com的 IP 地址。DNS 服务器返回
192.168.1.100。
2.HTTP 请求:
浏览器向
192.168.1.100发送 HTTP 请求。HTTP 请求中的
Host字段包含example.com。
3. 服务器处理:
- 物理服务器接收到请求后,根据
Host字段中的域名example.com将请求路由到虚拟机 A。
正是为了处理虚拟机这种复杂的 ip 地址关系,请求头中增加了新的字段 HOST。再提一句,cookie 也是在这个版本中新加的。
HTTP 2.0
1.1 的问题:带宽的利用率低。
TCP 的慢启动:TCP 的慢启动是一种用于控制网络拥塞的算法。在 TCP 连接建立初期,发送方会逐渐增加发送数据的速率,直到达到某个阈值,然后进入拥塞避免阶段。
同时开启的多条 TCP 连接相互竞争带宽
http 队头阻塞
所以出现 --- 多路复用 --- 解决 1.1 的后面两个问题
打造了一个二进制分帧层,将多个请求利用二进制分帧层处理成一帧一帧的请求,每一帧带上相应的 id 编号,服务器接收到所有的帧后,会根据相同的 ID 合并一个完整的请求。服务器响应该请求,将响应头和响应体发送给二进制分帧层,浏览器接收到响应帧后,自行合并成完整响应体。
多路复用当中可以给重要的资源添加标记,服务器会优先响应权重高的资源
通知只能最多开启一条 TCP 连接
在这个版本中,引入了许多新特性来提高网络性能,其中包括头部压缩。用于减少请求和响应头部的大小,从而提高网络传输效率。
使用 HPACK 算法来压缩请求和响应头部,它结合了静态压缩表和动态压缩表来实现高效压缩。压缩后可以减少带宽使用、加快响应时间、减少往返次数。
HTTPS VS HTTP
HTTPS 和 HTTP 的差别,应该都可以说出来 HTTPS 是加密用的,但是具体是怎么回事呢,在这里看看吧。
TLS 协议
对称加密:客户端和服务端都有一个相同的密钥,公用相同的一把锁,这样就只有你们才只能打开这把锁,但是你得先要让服务端拥有相同的密钥,这还是需要发送请求,在这个过程也有可能被别人窃取到。
非对称加密:为了使客户端和服务端都能拥有相同的密钥,就出现了公钥,公钥是另一把锁,每个人都知道怎么锁上这把锁,所以客户端将你的锁和密钥都使用这把锁锁起来,发送给服务端,这样即使被窃取别人也无法打开这把锁,只有服务端能够使用私钥开打公钥,得到客户端发送的密钥。
HTTP + TLS = HTTPS
HTTP 3.0
介绍这个最新版本前,先来说一下 UDP 协议。
UDP 和 TCP 的区别:
TCP:
可靠性:建立连接;流量拥塞控制;超时重传机制(假如你有一个 TCP 快递,买了床的框架、床头柜和床垫,如果床头柜丢失了,那么快递会暂停,直到给你补发的床头柜到了,再接着发剩下的床垫)
有序性(没有床头柜也不影响我的床啊,但是 TCP 始终贯彻保证到手内容不丢失,不打乱发送顺序)
UDP:
不可靠:无连接;流量拥塞控制;不管丢包
高效
注重实时性,比如打视频、打游戏、直播,卡了不要求回退回去
2.0 的问题:
TCP 的队头阻塞:主要因为超时重传,在传输数据包的过程中,一旦出现某一个包丢失,后续的所有数据包都要等待该丢失的数据包重新整理打包发送,后续包才能继续传输。
TCP 建立连接的延时
QUIC 协议
QUIC 协议 = TCP + UDP
实现了 TCP 的流量拥塞控制
集成了 TLS 加密
多路复用
快速握手
此协议是最新推出的,只有最近新出的设备才配有此协议,但大家的老设备没坏,所以并不好大范围支持
到这里 HTTP 协议的一些历史版本就介绍结束了。
3. 四次挥手
客户端向服务端发送断开连接请求
服务端接收到断开连接请求后,返回一个同意断开的响应,并进入到 CLOSE_WAIT 状态
服务端如果存在没有发送完毕的数据,会继续发送,进入 LAST_ACK 状态
客户端接收到服务端的应答,客户端进入 CLOSE_WAIT 状态持续 2MSL,并向服务端发送确认应答。在 2MSL 时间后自动进入 CLOSE 状态,服务端在接收到客户端的确认应答也进入 CLOSE 状态。
这里的 2MSL 是一段时间,这段时间是数据包能够存活的有效时长,确保服务端接收到确认应答,因为有可能服务端因为网络问题而没有接收到确认应答,而一直处于等待状态。
后面就是拿到 html、css 等数据来到浏览器渲染,也就涉及 DOM 树、OM 树、RENDER 树,页面排版之类的了,这里不继续絮叨。
结语
今天也是自己回顾总结了有关 HTTP 的一些知识点,这些都是个人观点,有不同看法,欢迎指正。大家一起加油!
作者:牛马先生