(Untitled)
工作后再来看浏览器输入URL后发生了什么?
从毕业到工作已经过去了一年半的时间,在春招中第一个被问到的问题就是浏览器输入URL后发生了什么,于是便把过程中发生了什么和工作中可能遇到的知识点与一些基础的计算机知识做了一下串联,如果有大佬看到有什么错误与欠缺,欢迎指正与补充
1、域名寻址阶段
过程
- 浏览器先查看本地硬盘host对应的域名规则,如果有直接使用该IP(浏览器缓存、操作系统缓存、本地host文件、路由器缓存)
- 浏览器发送DNS请求到本地DNS服务器,如电信、网通 ( ISP DNS缓存)
- 本地DNS服务器首先查询缓存记录,该过程为递归查询,如果有则直接返回,如果没有,则查询DNS根服务器
- DNS根服务器如果没有查到对应的域名与IP关系,则返回本地DNS服务器,使用域服务器继续查询,该过程为迭代查询
- www.xyz.abc.com 从 .com 域服务器一直查到 xyz.abc.com 域服务器 (顶级DNS服务器/根DNS服务器)
问题
1、什么是DNS
本质是一个IP与域名关系的电话本
DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。
2、DNS查询的两种方式:递归查询、迭代查询
递归查询
当局部DNS服务器自己不能回答客户机的DNS查询时,它就需要向其他DNS服务器进行查询。通过顺序下探的方式,一级一级的传递查询命令,最后得到的查询结果再一级一级返回给局部DNS服务器,再由局部DNS服务器返回给客户端。
迭代查询
当局部DNS服务器自己不能回答客户机的DNS查询时,也可以通过迭代查询的方式进行解析,局部DNS服务器不是自己向其他DNS服务器进行查询,而是把能解析该域名的其他DNS服务器的IP地址返回给客户端DNS程序,客户端DNS程序再分别向这些DNS服务器进行查询,直到得到查询结果为止。也就是说,迭代解析只是帮你找到相关的服务器而已,而不会帮你去查。
3、什么是DNS负载均衡?
在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的机器上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等。
2、建立TCP 连接
过程
- 浏览器打开一个socket 与目标 IP 地址端口通过三次握手建立TCP连接
问题
1、什么是TCP的 三次握手
- 客户端首先发送一个TCP的SYN=1,Seq=x的包到服务器端口,表示我将要发送请求。
- 服务器接收后,返回一个SYN=1,ACK=x+1,Seq=y的响应包,表示我已经收到通知,告知客户端发送请求。
- 客户端接收后,返回一个ACK=y+1,Seq=z的响应包,表示我要开始发送请求,准备被接受。
- TCP连接通道建立
2、为什么TCP链接的建立需要三次
为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误
问题的本质是,信道是不可靠的,但是我们要建立可靠的连接发送可靠的数据,也就是数据传输是需要可靠的。在这个时候三次握手是一个理论上的最小值,并不是说是tcp协议要求的,而是为了满足在不可靠的信道上传输可靠的数据所要求的。
3、TCP和UDP有什么区别
- 基于连接与无连接
- TCP要求系统资源较多,UDP较少
- TCP保证数据正确性,UDP可能丢包
- TCP保证数据顺序,UDP不保证
4、【进阶】SYN、ACK、Seq都代表什么,TCP报头中还有什么
5、【进阶】TCP 重传、滑动窗口、流量控制、拥塞控制都是什么
3、数据处理
过程
- 建立了TCP连接之后,发起一个HTTP(S)请求
- 服务器处理HTTP(S)请求,返回响应
- 浏览器处理状态码,决定是否读取缓存
问题
1、什么是HTTP 和 HTTPS,他们的区别是什么?
- HTTP: 超文本传输协议
- HTTPS:使用SSL/TLS加密的超文本传输协议
区别
- 安全性:https对内容使用SSL/TLS非对称加密的方式,更加安全
- 端口不同: http使用80端口;https使用443端口
- 效率:由于https存在加密,性能低于http
2、HTTPS 为什么需要证书?是怎么进行认证的?
什么是/为什么需要证书
证书都是由CA组织下认可的根证书Root签发的
为了防止中间人攻击,并验证服务器身份
宫缩流程:
- 客户端发送信息,带上浏览器所支持的SSL或者TLS版本
- 服务器返回确认使用的加密通信协议版本以及加密随机数和证书
- 客户端对证书进行验证,验证通过后本地生成用于改造对称加密算法的随机数
- 过证书中的公钥对随机数进行加密传输到服务端,服务端接收后通过私钥解密得到随机数,之后的数据交互通过对称加密算法进行加解密。
验证过程:
- 证书是否过期
- CA是否可靠(查询信任的本地根证书)
- 证书是否被篡改(用户使用CA根公钥解密签名得到原始指纹,再对证书使用指纹算法得到新指纹,两指纹若不一样,则被篡改)
- 服务器域名和证书上的域名是否匹配
3、什么是中间人攻击?
攻击者与发送者与接收者两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方 直接对话,但事实上整个会话都被攻击者完全控制。
4、http/证书被劫持/篡改该如何处理和预防?
- 使用https地址,并尽量配置服务端的http请求重定向至https
- 申请SSL证书,保证真实性,使用大机构CA颁发的证书,防止证书伪造
- header 中使用 Expect-CT,增加透明度
5、常用HTTP状态码有哪些?
- 1XX 信息,服务器收到请求,需要请求者继续执行操作
- 100 继续,客户端应继续其请求
- 2XX 成功,操作被成功接收并处理
- 200 成功
- 3XX 重定向,需要进一步的操作以完成请求
- 301 永久移动,请求的资源已被永久的移动到新URI
- 302 临时移动,资源只是临时被移动,客户端应继续使用原有URI
- 4XX 客户端错误,请求包含语法错误或无法完成请求
- 401 用户未认证
- 403 请求拒绝
- 404 无资源
- 5XX 服务器错误,服务器在处理请求的过程中发生了错误
- 500 服务器内部错误
- 501 服务器不支持请求的功能,无法完成请求
- 502 无效响应
6、HTTP的缓存类型分别的应用场景?
- 浏览器强制刷新 : Cache-Control: no-cache
- SPA 应用:使用协商缓存来保证资源文件的更新
7、什么是强缓存?
- 强制缓存是靠设置缓存失效时间,在有效时间内,缓存不会失效,浏览器会直接从浏览器缓存中读取资源
- 强制缓存主要是靠设置header中的expires和cache-control两个字段
- cache-control
- private 客户端可以缓存
- public 客户端和代理服务器都可缓存
- max-age=xxx 缓存的内容将在 xxx 秒后失效
- no-cache 不允许强缓存,只允许协商缓存
- no-store 不允许任何缓存
- expires 设置失效时间,但是权重会低于max-age
8、什么是协商缓存
- 首先向服务端发起一个请求,以获得缓存标识符,这次请求只会有返回只有响应头,没有body部分,返回后存储到缓存中
- 将缓存标识符发送给服务端,服务端如果比对成功,返回304状态码,告诉客户端可以使用缓存,如果比对不成功,直接返回新的资源。
- Last-Modified / If-Modified-Since 基于时间
- Last-Modified 服务器在响应请求时,告诉浏览器资源的最后修改时间
- If-Modified-Since 再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间
- Etag / If-None-Match 基于标识 优先级高于Last-Modified / If-Modified-Since
- Etag 资源在服务器的唯一标识
- If-None-Match 再次请求服务器时,服务器客户端缓存数据的唯一标识
9、什么是CDN?CDN的原理是什么?
通过在网络各处部署节点服务器,实现将源站内容分发至所有CDN节点,使用户可以就近获得所需的内容
原理:本地DNS服务器通过CNAME方式将最终域名请求重定向到CDN服务
- 用户在浏览器输入要访问的网站域名,向本地DNS发起域名解析请求。
- 域名解析的请求被发往网站授权DNS服务器。
- 网站DNS服务器解析发现域名已经CNAME到了www.example.com.c.cdnhwc1.com。
- 请求被指向CDN服务。
- CDN对域名进行智能解析,将响应速度最快的CDN节点IP地址返回给本地DNS。
- 用户获取响应速度最快的CDN节点IP地址。
- 浏览器在得到速度最快节点的IP地址以后,向CDN节点发出访问请求。
- 如果资源不存在,CDN节点回源站拉取用户所需资源,将回源拉取的资源缓存至节点
- CDN节点将用户所需资源返回给用户。
10、option,状态码多少,什么时候是100,为啥要有option ,没有option的post请求叫什么
- option请求也称为预检请求(preflight request)。
- option 为了获取服务器支持的HTTP请求方法及检查服务器的性能,来保证后续请求能够正常完成
- 不是所有的cors都会发生预检请求,当请求为简单请求时,会不发送option请求
11、简单请求和复杂请求
满足以下条件的请求即为简单请求,其余的都是复杂请求:
- 请求方法:GET、POST、HEAD
- 除了以下的请求头字段之外,没有自定义的请求头
- Accept
- Accept-Language
- Content-Language
- Content-Type
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
- Content-Type的值只有以下三种
(Content-Type一般是指在post请求中,get请求中设置没有实际意义)
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
- 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器
(未验证)
- XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问
- 请求中没有使用 ReadableStream 对象
(未验证)
4、关闭TCP链接
过程
- 浏览器接收到http相应后,根据情况选择关闭TCP连接或者保留重用
问题
1、关闭TCP连接的四次握手过程
- 主动方发送fin =1,ack=z,seq=x
- 被动方发送ack=x+1,seq=z
- 被动方发送fin =1,ack=x,seq=y
- 主动方发送ack=y,seq=x
2、关闭TCP连接为什么需要四次握手
TCP没有半开方法的传输方法,但是有半关传输方法
5、 页面渲染
过程
- 渲染进程解析
HTML
生成DOM
树 - 解析
CSS
生成 CSSOM规则树 - 加载或执行
JavaScript
- 将DOM树与CSSOM规则树合并在一起生成渲染树(
Render Tree
) - 主线程遍历渲染树,生成一系列的绘画记录(paint records),生成绘制列表
- 调用 GPU 绘制,合成图层,显示在屏幕上。
问题
1、什么是线程与进程?
- 进程是资源分配的最小单位
- 线程是CPU调度的最小单位
- 线程是跑在进程里面的
2、浏览器(chrome为例)有哪些进程?进程间是如何进行协作的?
- 浏览器进程 (Browser Process):负责浏览器的TAB的前进、后退、地址栏、书签栏的工作和处理浏览器的一些不可见的底层操作,比如网络请求和文件访问。
- 渲染进程 (Renderer Process):负责一个Tab内的显示相关的工作,也称渲染引擎。
- 插件进程 (Plugin Process):负责控制网页使用到的插件
- GPU进程 (GPU Process):负责处理整个应用程序的GPU任务
3、为什么要将JS文件放到页面底部进行加载?(渲染阻塞)
当浏览器遇到一个 script 标记时,DOM 构建将暂停,直至脚本完成执行,然后继续构建DOM。每次去执行JavaScript脚本都会严重地阻塞DOM树的构建,如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM还没有下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建。
4、渲染树和DOM是否一一对应?
不对应
- DOM 树构建时当遇到JavaScript脚本,就要暂停 DOM 解析,先去执行Javascript,因为在JavaScript可能会操作当前已经生成的DOM节点。(javascript是可能操作当前已经生成的DOM节点)
- DOM 树构建时当遇到 JavaScript 脚本,就要暂停 DOM 解析,先去执行 JavaScript,同时 JavaScript 还要判断 CSSOM 是否解析完成,因为在 JavaScript 可能会操作 CSSOM 节点,CSSOM 节点确认解析完成,执行 JavaScript 再次回到 DOM 树创建。(所以这里也可以所CSS解析间接影响DOM树创建)
5、渲染树形成过程可以做哪些优化?
- CSS 资源先于 JavaScript 资源引入。样式文件应当在 head 标签中,而脚本文件在 body 结束前,这样可以防止阻塞的方式。
- 尽量减少在 JavaScript 中进行DOM操作。
- 简化并优化CSS选择器,尽量将嵌套层减少到最小。
- 修改元素样式时,更改其class属性是性能最高的方法。
6、什么是渲染树?
在有了 DOM
树和 CSSOM
之后,需要将两者结合生成渲染树 Render Tree
,并且这个过程会去除掉那些 display: node
的节点。此时,渲染树就具备元素和元素的样式信息。
伪元素虽然在DOM上不可见,但是在渲染树上是可见的。
8、回流、重绘
- Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)(生成布局(flow),即将所有渲染树的所有节点进行平面合成)
- Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素(将布局绘制(paint)在屏幕上)
7、重排/回流(reflow)和重绘(repaint)
- 重绘:某些元素的外观被改变,例如:元素的填充颜色
- 重排:重新生成布局,重新排列元素。
重绘不一定导致重排,但重排一定会导致重绘
页面初始渲染,这是开销最大的一次重排
减少重绘和重排的⽅法
- 不在布局信息改变时做 DOM 查询
- 使⽤ cssText 或者 className ⼀次性改变属性
- 使⽤ fragment
- 对于多次重排的元素,如动画,使⽤绝对定位脱离⽂档流,让他的改变不影响到其他元素
重排属性:
- width、height、padding、border、margin、position、top、left、bottom、right、float、clear
重绘属性:
- color
- border
- box-shadow
- background
8、requestAnimationFrame
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行,回调函数执行次数通常是每秒60次
9、浏览器与node的Event Loop
浏览器的Event Loop
- 执行同步代码
- 执行当前队列尾部所有微任务
- 必要的话渲染UI(浏览器是60hz刷新率,所以16ms一帧更新一次UI)
- resize/scroll事件(16Ms一次,自带节流)
- 判断是否触发media query
- 更新动画发送事件
- 全屏操作事件
- 执行requestAnimationFrame回调
- 执行intersectionObserver回调
- 更新UI
- 如果还有时间,自行requestldleCallback
node 的 Event Loop
分为六个阶段
- timers:这个阶段执行定时器队列中的回调,比如setTimeout()和setInterval()
- I/O callbacks:这个阶段执行几乎所有的回调。但是不包括close事件,定时器和setImmediate的回调。
- idle,prepare:仅在内部使用。
- poll:等待新的I/O事件,node会在一些特殊的情况下使用
- check:setImmediate()的回调会在这个中执行。
- close callbacks:例如socket.on('close', ...)执行close的回调。
poll阶段
当有数据或者连接传入事件循环的时候,先进入的是poll阶段,这个阶段,先检查poll queue中是否有事件,有任务就按先进先出的顺序执行回调,如果队列为空,那么会先检查是否有到期的setImmdiate,如果有,将其的callback推入check队列中,同时还会检查是否有到期的timer,如果有,将其callback推入到timers队列中。如果前面两者都为空,那么直接进入I/O callback,并执行这个事件的callback。
check阶段
check阶段专门用来执行setImmidate的回调函数。
close阶段
用于执行close事件的回调函数
timer阶段
用于执行定时器设置的回调函数
I/O callback阶段
用于执行大部分I/O事件的回调函数。
process.nextTick
这个钩子在node的事件循环模型中没有提及,但是node中有一个特殊的队列,nextTick queue。在node事件循环进入到下一个阶段的时候,都会去检测nextTick queue中有没有清空,如果没有清空,那么就会去清空nextTick queue中的事件。
循环过程
循环开始之前
- 所有同步任务
- 脚本任务中发送的api请求
- 规划定时器同步任务的生效时间
- 执行process.nextTick()
开始循环
- 第一种情况
- 清空当前循环内的 Timers Queue,清空NextTick Queue,清空Microtask Queue
- 清空当前循环内的 I/O Queue,清空NextTick Queue,清空Microtask Queue
- 进入poll阶段
- 清空当前循环内的 Check Queue,清空NextTick Queue,清空Microtask Queue
- 清空当前循环内的 Close Queue,清空NextTick Queue,清空Microtask Queue
- 第二种情况
- 先进入poll阶段
- 清空当前循环内的 Check Queue,清空NextTick Queue,清空Microtask Queue
- 清空当前循环内的 Close Queue,清空NextTick Queue,清空Microtask Queue
- 清空当前循环内的 Timers Queue,清空NextTick Queue,清空Microtask Queue
- 清空当前循环内的 I/O Queue,清空NextTick Queue,清空Microtask Queue
12、同步方法和异步方法、宏任务和微任务
- 同步任务:会立即执行的任务
- 异步任务:不会立即执行的任务(异步任务又分为宏任务与微任务)
- 常见的异步任务:Ajax,Dom事件操作,setTimeOut,promise的then方法,Node读取文件
13、 宏任务与微任务
宏任务
(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。
宏任务包含:
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)
微任务
microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。
微任务包含:
Promise.then
Object.observe
MutaionObserver
process.nextTick(Node.js 环境)
运行机制
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:
- 执行一个宏任务(栈中没有就从事件队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
参考文章
- DNS :从输入URL到页面展示,你想知道些什么?
- TCP:30张图解: TCP 重传、滑动窗口、流量控制、拥塞控制
- HTTP:HTTP详解
- CDN:CDN · 前端工程师面试宝典
- 渲染树:渲染树的形成原理你真的很懂吗?
- 浏览器原理:精读 - 浏览器渲染原理