用户输入 url 到页面展现的过程
这是一道很经典的面试题了,考察点也是很多,dns 解析、http、浏览器渲染的过程等等,github 上也有个仓库详细的解释了这个过程,what-happens-when,所以我按照自己的思路再提炼一次
首先,计算机是不会和人打交道的,那么要让它打交道我们需要输出和输入设备,这里我们需要输入设备键盘、鼠标和输出设备显示器,当然了我们还需要一个浏览器,浏览器是一个软件,是一个可以运行在计算机上供用户浏览网页的软件
当我们输入 url 的时候,发生了什么?我们在按键,键盘有按下和抬起的区别,当我们按下的时候系统中断,并且键盘驱动取得当前按键的扫描码发送给 CPU,CPU 通过对应表找到显示字符并发送给浏览器,浏览器显示该字符
- 按下和抬起的时候键盘电路快速的开和关,所以避免误判,这里会做防抖处理,并且按下后长时间不放会做多次按键处理
- 系统中断这个有点像 angularJs 的脏值检测,不是通过轮询来实现数据检测,而是在特定的事件发生后进入检测,系统中断也是如此,不然的话要一直检测输入设备的状态 low
- 对应表是扫描码和显示字符的对应
- 输入过程中浏览器会根据输入历史和建议显示相近的字符供用户选择
url 输入完毕后按下回车,这时候浏览器会解析 url 并验证 url 的正确性,如果协议或域名不正确则会传递给设置的搜索引擎,正确的话先去 HSTS list 中匹配该网站是否只使用 https 连接
- 解析 url 步骤会转化非 ASCII 字符
- Chrome HSTS list 查看:地址栏输入
chrome://net-internals/#hsts
- 不在 HSTS list 中也可以通过设置请求头来实现 HSTS 访问:
add_header Strict-Transport-Security: max-age=31536000; includeSubDomains; preload;
开始解析域名,也就是常说的 DNS,DNS 做过网站的朋友应该是知道的,网站是要买域名的,但是网络根本不知道你的域名和服务器对应关系,所以一般买完域名要域名解析,让网络知道 aaa.com->10.10.10.10,域名其实相当于 alias,我们想要找到目标服务器只能通过 ip,所以会先检查浏览器的 DNS 缓存,如果找到了直接拿到 ip 访问网站,如果没有,去系统缓存中查找,没找到会去你的路由缓存或者 ISP 服务商缓存中找,如果还没找到,去根域名服务器进行递归搜索
- Chrome DNS 缓存:
chrome://net-internals/#dns
- 系统缓存包括 hosts 文件,hosts 每个系统存放的位置是不同的,但是打开都能看到一个域名和 ip 对应关系,也可以自己设置,开发人员应该很熟悉了
- ISP 服务商就是你的网络服务提供商,电信啊长城啊这些,长城辣鸡不解释,npm install 能用算我输
- 全球有13组根域名服务器(名字 A 至 M),离我们最近的在日本
- Chrome DNS 缓存:
拿到 ip 后开始 http 请求,http 是应用层的协议,我们要想进行网络连接需要传输层的协议 TCP ,建立 TCP 连接就到了我们熟悉的
三次握手
了,三次握手后客户端和服务端建立了 TCP 连接,可以传输数据了,数据传输完成后要关闭连接,需要四次挥手
- 计算机的世界里是很注重规范的,规范其实就是约定,和服务器建立网络连接也是,要遵循约定,所以 http、ftp 这些其实都是名词,都是约定的名词,以后还可能会有 httpa、httpb 都说不定,至于为什么叫 http,英文缩写咯
- TCP 和 UDP 其实区别就在于是否面向连接, UDP 不管三七二十一拿到数据就干,TCP 需要建立连接并且收发确认,所以 UDP 的传输效率是比 TCP 要高的
- 三次握手:
- 第一次握手客户端发出连接请求报文段,这时首部中的同步位 SYN 置为1,同时初始序号 seq = x,这时客户端进入 SYN-SENT 状态
- 第二次握手服务端收到连接请求报文段,将 SYN 和 ACK 都置为1,并且确认 ack = x + 1,同时也初始化序列号 seq = y,这时服务端进入 SYN-RCVD 状态
- 第三次握手客户端收到服务端的确认后,将 ACK 置为1,并且确认 ack = y + 1,而自己的初始序号 seq = x + 1,这时 TCP 连接建立,客户端和服务端进入 ESTABLISHEN 状态
- 四次挥手:
- 第一次挥手数据传输完毕,客户端向服务端发送连接释放报文段,将首部 FIN 置为1,初始序号 seq = x,这时客户端进入 FIN-WAIT-1 状态
- 第二次挥手服务端收到后将首部 ACK 置为 1,并且确认 ack = x + 1,初始序号 seq = y,这时服务端进入 CLOSE-WAIT 状态,TCP 属于半关闭状态,因为要确认服务端这边也没有数据要发送了
- 第三次挥手客户端进入 FIN-WAIT-2 状态,等待服务端发送连接释放报文段,这时候服务端没有数据发送,服务端将首部 FIN、ACK 置为1,初始序号 seq = n,确认 ack = x + 1,这时服务端进入 LAST-ACK 状态
- 第四次挥手客户端收到后将首部 ACK 置为1,初始序号 seq = x + 1,确认 ack = n + 1,进入到 TIME-WAIT 状态,经过 2MSL 后客户端进入 CLOSED 状态
- 这里看到的 SYN、ACK、MSL、FIN 都是啥?
- MSL - Maximum Segment Lifetime 的英文缩写,可译为最长报文段寿命,它是干什么的?它的值是用来确认 TIME-WAIT 状态的周期( MSL 的两倍)
- SYN - Synchronous 的英文缩写,表示建立连接
- ACK - Acknowledgement 的英文缩写,表示响应连接
- FIN - Finish 的英文缩写,表示关闭连接
- seq - Sequence Number 的英文缩写,表示序号
- ack - Acknowledgment Number 的英文缩写,表示确认号
- TCP 会话的每一段都会包含 seq,seq 初始是随机的,ack 是已经成功接收到的数据字节序号 + 1,换个角度 ack 就是下次要接收数据的 seq