面试题-从输入url到页面展示发生了什么
解析过程
1、DNS解析
2、TCP连接
3、发起http请求
4、服务器处理http请求
5、服务器响应http请求
6、浏览器渲染页面
7、连接结束
DNS解析
输入网址,浏览器并不知道要去哪里找资源,需要DNS递归查询对应IP
- DNS递归查询首先是在本地服务器进行查询,本地服务器找不到后再向根域名服务器查询,根域名服务器找不到再向上一级顶级com域名服务器查找。直到最终找到并返回IP,然后本地域名服务器会将该ip缓存起来,供下次使用。比如输入www.google.com,那么查询过程为.->.com->google.com->www.google.com
- 此处优化方法:
DNS缓存:浏览器、系统(host文件)、路由器、ISP DNS缓存(互联网提供商)、本地域名服务器等都有缓存
DNS负载均衡:根据地理位置、服务器负载量等来选择最合适的一个服务器来进行查询
TCP连接:三次握手,四次挥手
TCP报文结构:

TCP报文结构中有固定的20字节的首部,里面有源端口、目的端口。序号、确认号、校验和、数据偏移等
- seq(序号): TCP连接的数据字节流中的每一个字节都有一个序号,seq表示的是本报文发送的第一个字节的序号。
- ack(确认号):表示期望收到的下一个报文段第一个字节的编号
- 标志位SYN(同步标识):本bit位为1时表示发送的是一个连接请求或者连接接受的报文
- 标志位ACK(确认标识):本bit位为1 表示确认号有效,表示确实收到seq为x的包,下次会回复ack = x + 1的值
- 标志位FIN(完成标识):本bit位为1时,释放一个连接。表示发送端的数据已全部发送,要求释放传输通道。
- 标志位RST(复位标识):为1时表示本次TCP连接出现严重错误,需要重新连接
- 标志位PSH(推送标识):推送位。
- 标志位URG(紧急标识):紧急bit位,表示紧急指针有效,这意味着不必等待前段数据被响应处理完即可发送给接收端
三次握手过程
从网上盗的图:

- 白话讲解
- 第一次握手:客户端:喂,听得到吗?
- 第二次握手:服务器:听得到,你听得到我吗?
- 第三次握手:客户端:听得到,咱们开始传输吧。
- 专业讲解:
- 第一次握手:客户端主动发起请求,第一个报文首部标志位为:SYN=1,seq=x
- 第二次握手:服务端表示收到请求并响应请求:SYN=1, ack=x+1,seq=y,ACK=1
- 第三次握手:客户端向服务器发送确认报文:seq=y+1, ACK=1。此时连接已建立
四次挥手

- 白话讲解(假设客户端先请求断开):
- 第一次挥手:客户端:我说完了,咱们断开吧
- 第二次挥手:服务端:收到,我还没说完,¥@#(%&……
- 第三次挥手:服务端:我说完了,咱们断开吧
- 第四次挥手:客户端:收到!(此时已断开,如果长时间没收到答复,也会默认断开)
- 专业解释:
- 第一次挥手:客户端:FIN=1,seq=u,客户端已停止向服务端发送数据
- 第二次挥手:服务端:ack=u+1,seq=v,客户端已停止,但服务端还在发送数据
- 第三次挥手:服务端:内容发送完成后,在最后一段报文的首部:FIN=1,ACK=1,ack=u+1,seq=w,并且不再发送数据
- 第四次挥手:客户端:对服务器应答,表示确认断开,ACK=1,seq=u+1,ack=w+1
TCP与UDP的区别
UDP报文结构:
16位源端口,16位目标端口,16位UDP长度,16位UDP校验和,数据
TCP是面向连接的,传输之前必须先握手,UPD不面向连接,直接传就完事了,但是对方收没收到是没底的。因此TCP更安全可靠,UDP效率更高
OSI五层模型

TCP属于传输层,TCP连接建立起来后会通知上层应用,进行其他活动。根据OSI(Open System Interconnect,开放式系统互联)五层模型,它的上层是应用层,下层还有网络层、数据链路层和物理层。其中,发送方从上到下一层层包装,分别依次序加上TCP首部、IP首部、以太网首部,通过物理层传输到接收方,接收方再由下到上逐层解析,最后到达应用层。
http请求
http请求
TCP连接建立起来后开始发送一个http请求,http请求报文由请求行(request line)、请求头(header)、空行和请求数据4个部分组成
- 请求行
- 请求方法:GET(http/0.9),POST(http/1.0),HEAD(http/1.0),PUT(http/1.1),DELETE(http/1.1),OPTIONS(http/1.1),TRACE(http/1.1),CONNECT(http/1.1)
- 请求地址:URL(统一资源定位符),组成格式:<协议(http/https)>://
:<端口>/<路径> - 协议版本:http0.9、http1.0
- 请求头
常见http请求头:
- Host: 服务器IP地址或域名
- User-Agent: 发送请求的客户端系统和浏览器信息
- Connection: Keep-Alive 等,表示连接状态
- Accept-Encoding: 通知服务端可以发送的数据压缩格式
- Accept-Charset: 通知服务端可以发送的编码格式
- Accept-Language: 通知服务端可以发送的语言
- Cache-Control: 通过指定指令来实现缓存机制。比如private,public、no-cache
- Cookie: 存储一些用户信息、sessionId等
- Range: byte=0-5 指定第一个字节和最后一个字节的位置,告诉服务器自己想提取哪些字节
- Content-Security-Policy 用来开启CSP(内容安全策略)
- 请求数据
可选有或者没有,比如name=Alice
http响应
http响应报文主要包含状态行、响应头部、空行及响应数据组成。
- 状态行:主要由协议版本、状态码、状态码描述组成
- 协议版本:http/1.1
- 状态码:见http发展历史;
- 状态码描述:当前状态的描述。比如: 200 ok
- 响应头部
常见http响应头:
- Content-Type: text/html;charset=UTF-8 告诉客户端,资源文件的类型,还有字符编码,客户端据此进行解码
- Content-Encoding: 告诉客户端,服务端发送的资源都是gzip编码的
- Date: 服务器发送资源的GMT(格林尼治时间)时间
- Server: 服务器和相对应的版本
- Transfer-Encoding: chunked 通知客户端,服务器发送的资源是分块发送的
- Last-Modified: 最后一次更新时间
- Connection: Keep-Alive 等,表示连接状态
- Access-Control-Allow-Origin: * 表示所有网站可以跨域资源共享
- Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS 允许哪些方法访问
- Access-Control-Allow-Credentials: true 是否允许发送Cookie
- Content-Range 响应覆盖的范围和整体长度
- ETag 判断服务器资源是否更改
- Refresh 用于重定向
- 响应数据
1 | HTTP/1.1 200 OK // 状态行 |
- http缓存优化方案
在一次请求中,服务器会返回客户端Last-Modified时间,那么下次请求中,客户端就可以在请求头中添加If-Modified-Since+时间,如果没变,服务端会回状态码304,那么客户端就可以继续使用本地缓存展示内容。如果改变了,就返回200,并返回新的资源。
或者使用ETag(资源标识符)。在一次请求中,服务端会返回ETag,它是一串根据内容生成的字符串。下次请求时,客户端会加上请求头:
If-None-Match:33a64df551425fcc55e4d42a148795d9f25f89d4,服务端将该值与资源的ETag进行比较,如果相同,返回304,如果不同,就返回200和新的资源。
https请求
https与http的区别在于,应用层中,应用数据先经过SSL/TLS进行加密,再经过TCP连接
加密原理
客户端在向服务端发送请求时,服务端会返回自己的公钥(保险箱),客户端将数据根据服务端的公钥加密(把数据放在保险箱里),再返回给服务端,服务端用之前给客户端公钥相匹配的私钥(保险箱钥匙)解密,即得到传输的数据。
为了保证服务端返回的公钥(保险箱)没有被中间黑客替换,需要证明该公钥(保险箱)确实是服务端给的。这时候数字证书(身份证)登场了。数字证书(身份证)是政府机构或者一些受信任的组织(证明人)为网站做的证明。它是CA将私钥发放给受信任的机构,公钥会发给各客户端。服务端在给客户端发送公钥时就可以用该证书加密公钥,发送给客户端,客户端用CA的公钥解密并验证完整性,通过后再传输数据。所以,流程变化如下:
- 客户端发送请求
- 服务端返回自己的用数字证书加密过的公钥
- 客户端解析证书,包括正确性和完整性
- 传送加密信息
- 服务端解密信息,并使用客户端传给服务端的私钥加密信息
- 服务端向客户端传输加密后的信息
- 客户端解密
SSL/TLS握手过程
- 客户端向服务端发送Client Hello信息,里面包含一个客户端生成的随机数Random1,支持的加密套件、SSL版本
- 服务端返回Server Hello消息。服务端根据刚才客户端上报的支持的加密套件,确定一种加密方式,在这条信息中一块传给客户端。同时生成另一个随机数一块传给客户端
- Certificate: 服务端将自己的证书下发给客户端,客户端用对应公钥解密,取出其中的公钥
- Certificate Request(可选): 服务端要求客户端上报证书。
- Sever Hello Done: 服务端通知客户端 Server Hello 结束
- Certificate Verify: 客户端收到证书后,先从CA验证证书是否合法,合法后取出公钥。再生成一个随机数Random3,用公钥非对称加密(RSA等)Random3,生成PreMaster Key。
- Client Key Exchange:客户端根据服务器传来的公钥生成了 PreMaster Key后,将这个 key 传给服务端,服务端再用自己的私钥解出这个 PreMaster Key 得到客户端生成的 Random3。至此,客户端和服务端都拥有 Random1 + Random2 + Random3,两边再根据同样的算法就可以生成一份秘钥,握手结束后的应用层数据都是使用这个秘钥进行对称加密。
页面渲染
浏览器拿到HTML文档后,开始解析并渲染页面
渲染过程
- 解析HTML生成DOM(文档对象模型)树
- 解析CSS生成CSSOM(CSS对象模型)树
- 将DOM树与CSSOM树结合为渲染树
- 根据渲染树设计布局(layout),计算节点大小、布局
- 绘制节点
JS解析
浏览器的内核是多线程的,一个浏览器至少会有三个线程:javascript处理线程、GUI渲染线程、事件触发线程
- JavaScript是事件驱动型的单线程语言,js处理引擎也是单线程,js一直等待着任务队列中任务的到来,然后加以处理
- GUI渲染线程负责浏览器的渲染工作,浏览器发生回流或重绘时该线程就会触发。GUI线程与JavaScript线程是互斥的。只要JavaScript线程执行,GUI渲染线程就会挂起。一般是等待JavaScript线程执行结束,再从等待队列中取出GUI渲染线程执行。
- 事件触发线程。当一个事件被触发时,该线程会把该事件添加进事件触发队列的队尾,等待js引擎处理。
- JS文件默认是阻塞进程的,所以为了用户体验,最佳实践是link标签放head标签而script放body底部。或者加上defer,延迟加载;加上async,异步加载。
注意点
参考文档
https://www.jianshu.com/p/668970142765
https://segmentfault.com/a/1190000013522717
https://juejin.im/post/5c17d3cd5188250d9e604628
https://my.oschina.net/elitetao/blog/781227
https://developers.weixin.qq.com/community/develop/article/doc/000046a5fdc7802a15f7508b556413
https://www.jianshu.com/p/7158568e4867