从在浏览器中输入一个网址开始说起
前端面试的时候经常会被问到 在浏览器中输入一个网址之后发生了什么,我们就从这个问题开始说起
在浏览器中输入一个网址之后发生了什么
-
DNS解析
-
提供的是一种主机名到 IP 地址的转换服务,就是我们常说的域名系统。
-
DNS查询发起
- 当你在浏览器中输入一个域名(如 www.example.com ) 并按下回车时,浏览器会发起一个DNS查询请求。
-
查询本地DNS缓存
- 浏览器会首先检查本地的DNS缓存,看看是否已经缓存了该域名的IP地址。如果缓存中存在该信息,则直接使用缓存中的IP地址完成访问
-
递归DNS解析
- 如果本地缓存中没有该域名的IP地址,浏览器会将请求发送到本地的DNS解析器(通常是操作系统提供的DNS解析服务)。
- 本地DNS解析器会进行递归查询,直到找到域名的IP地址或确定该域名无效
-
查询DNS服务器
- 本地DNS解析器首先查询根DNS服务器,以获取顶级域名服务器(如 .com、.org)。
- 根DNS服务器会返回对应顶级域名服务器的地址。
- 本地DNS解析器接着查询顶级域名服务器,获取权威DNS服务器(提供 example.com 的域名解析)。
- 最后,本地DNS解析器查询权威DNS服务器,获取最终的IP地址。
-
缓存和返回结果
- 一旦找到了域名的IP地址,本地DNS解析器将结果缓存,并返回给浏览器。
- 浏览器使用这个IP地址来建立与目标服务器的连接,并加载网站内容。
-
DNS响应缓存
-
DNS响应会被缓存,包括在本地DNS解析器和浏览器缓存中。这有助于加速未来对相同域名的访问
-
-
-
跟目标服务器之间建立连接
三次握手(SYN (synchronize)是请求同步的意思,ACK是确认同步的意思)
-
客户端向服务端发起请求连接请求
- 建立连接时,客户端发送SYN包到服务器,并进入SYN_SENT状态,等待服务器确认,其中SYN就是同步序列编号
-
服务端收到请求后向客户端返回确认报文
- 服务器收到SYN包,必须确认客户的SYN,同时自己也发送一个SYN包,即是SYN+ACK包,此时服务器进入SYN_RECV状态
-
客户端收到确认后向服务端给出确认
-
客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK,此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
-
如果是https连接,那么在三次握手之后还需要进行一次TLS连接
-
秘钥协商过程
-
客户端发送自身支持的加密算法
-
服务器端选择一种加密算法,同时返回数字证书。(证书包含公钥)
-
客户端确认证书有效。
-
HTTPS 握手过程中,客户端如何验证证书的合法性
- 校验证书的颁发机构是否受客户端信任。
- 通过 CRL 或 OCSP 的方式校验证书是否被吊销。
- 3 对比系统时间,校验证书是否在有效期内。
- 通过校验对方是否存在证书的私钥,判断证书的网站域名是否与证书颁发的域名一致。
-
-
客户端生成随机数,并使用证书中的服务器公钥加密,然后发送给服务器。
-
服务器端使用私钥解密,获得随机数。
-
双方使用第 2 步确定的加密算法,把随机数进行加密,即可获得相同的对称加密秘钥。
-
-
发送请求
-
HTTP1.0 和 HTTP1.1
-
缓存处理
- 在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
-
支持断点续传 range.
- 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
-
长连接
- HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
-
错误通知的管理 增加了新的状态码
- 在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
-
增加Host头处理
- 在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
-
http2
-
http2多路复用
-
多路复用代替了 HTTP1.x 的序列和阻塞机制,所有的相同域名请求都通过同一 个 TCP 连接并发完成。
-
在 HTTP1.x 中,并发多个请求需要多个 TCP 连接,浏览器为了控制资源会有 6-8 个 TCP 连接都限制。
-
HTTP2 中同域名下所有通信都在单个连接上完成,消除了因多个 TCP 连接而带来的延 时和内存消耗。
-
单个连接上可以并行交错的请求和响应,之间互不干扰
- 解决队头阻塞的问题
-
-
多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
-
服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。
- 服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。
-
HTTP2 采用二进制格式传输,取代了 HTTP1.x 的文本格式,二进制格式解析更 高效。
- 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
-
header压缩,(HPACK算法) 如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
-
-
http3
-
基于udp
- 实现了类似于TCP的多路复用数据流、传输可靠性等功能,这套功能被称为QUIC协议
-
解决队头阻塞问题
- 通过quic流 —— quic帧 —— quic包—— 每个包带有唯一id 如果丢失了只需要请求重传对应的包
-
0-rtt
- http2中tls握手1-rtt 三次握手1-rtt 一共2-rtt
- http3中tls和quic握手混合在一起了所以只要1-rtt
- 如果需要恢复通信,则不需要重新连接 直接通信所以在恢复通信的时候0-rtt
-
基于 QUIC 的传输(QUIC Protocol)Quick UDP Internet Connection
-
HTTP/3 使用 QUIC 作为传输层协议。QUIC 是一种基于 UDP 的协议,设计上比 TCP 更快速,具有更好的性能和更低的延迟。
-
更好的拥塞控制(Improved Congestion Control): QUIC 提供了更先进的拥塞控制算法,改善了网络性能和流量管理。
-
连接迁移(Connection Migration): QUIC 允许连接在不同的网络之间迁移(例如从 Wi-Fi 切换到移动网络),而不会中断当前的连接。
-
内置加密(Built-in Encryption): QUIC 内置了加密功能,所有的通信都是加密的,这提升了安全性并减少了对额外加密层的需求。
-
减少连接建立时间(Reduced Connection Establishment Time): QUIC 通过减少连接建立的轮次来降低延迟,从而加速了连接的建立过程。
-
请求方式
-
get
-
应该只被用于获取数据,参数会体现在url中,不安全且能带的数据量较小
- 数据量小是因为浏览器对uri的长度限制 并不是http的规定
-
-
post
- 用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用 不会作为URL的一部分,更加安全。可以携带大量的数据
-
delete
- 删除指定的资源
-
patch
- 对资源应用部分修改
-
option
-
触发条件
-
跨域
-
探测服务器支持的 HTTP 方法
-
API 网关或负载均衡器
-
-
使用了下面任一HTTP 方法:
- PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH (即get/post请求之外的方法)
-
-
-
人为设置了以下集合之外首部字段:
- Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width
-
-
-
Content-Type 的值不属于下列之一:
- application/x-www-form-urlencoded、multipart/form-data、text/plain
-
-
-
作用
- 在跨域情况下 要首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求
- 检测服务器所支持的请求方法
-
-
head
- 类似get请求,但只返回响应头
-
put
- 向指定资源位置上传其最新内容
-
- 返回响应
返回响应的过程中,为了性能上的考虑,大部分的请求都应该选择好缓存策略
-
通常浏览器缓存策略分为两种:强缓存和协商缓存,并且缓存策略都是通过设置 HTTP Header 来实现的。
-
浏览器对于缓存的处理是根据第一次请求资源时返回的响应头来确定的
-
强缓存
-
强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容
-
expires
- http1.0的规定
- 通过设置expires头中的时间
- 缺点:它是服务器返回的一个绝对时间,客户端如果修改了时间,结果可能不准
-
cache-control 优先级更高
- http1.1的规定 时间是以客户端的时间为准。是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示
- no-cache: 协商缓存
- max-age:缓存的内容会在这个值之后过期
- no-store:全部不缓存
- public:共有缓存 可被代理服务器缓存 允许用户间共享
- priavte:私有缓存 只被当前浏览器缓存
- must-revalidate: 必须再次检查信息是否过期,这时候返回的代码就不是200而是304
-
强缓存就是浏览器本地根据服务器设置的过期时间来判断是否使用缓存,未过期则从本地缓存里拿资源,已过期则重新请求服务器获取最新资源。
-
强缓存优先级大于协商缓存,即两者同时存在时,如果强缓存开启且在有效期内,则不会走协商缓存。
-
-
协商缓存
-
协商缓存则是浏览器本地每次都向服务器发起请求,由服务器来告诉浏览器是从缓存里拿资源还是返回最新资源给浏览器使用。
-
last-modified If-Modified-Since
- 再向服务器发送一次请求判断资源在时间规定内是否有变化
- 缺点:但是有时候也会服务器上资源其实有变化,但是最后修改时间却没有变化的情况
- 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在response的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间
- 浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值:
- 根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化
- 分布式系统里多台机器间文件的Last-Modified必须保持一致,以免负载均衡到不同机器导致比对失败;
-
etag if-none-match 优先级更高
- etag类似一个hash 不同文件对应不同的hash
- if-no-match请求服务端资源时如果资源没有变化,就不返回内容 从缓存中加载资源
- 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在response的header加上ETag的header,这个header是服务器根据当前请求的资源生成的一个唯一标识,这个唯一标识是一个字符串,只要资源有变化这个串就不同,跟最后修改时间没有关系
- 浏览器再次跟服务器请求这个资源时,在request的header上加上If-None-Match的header,这个header的值就是上一次请求时返回的ETag的值
- 服务器再次收到资源请求时,根据浏览器传过来If-None-Match和然后再根据资源生成一个新的ETag,如果这两个值相同就说明资源没有变化,否则就是有变化
- 由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化
- 分布式系统尽量关闭掉ETag(每台机器生成的ETag都会不一样);
-
etag 不适合用负载均衡的情况
-
-
如果什么缓存策略都没设置,那么浏览器会怎么处理?
- 浏览器会采用一个启发式的算法,通常会取响应头中的 Date 减去 Last-Modified 值的 10% 作为缓存时间。
-
对于很少变化的静态资源(如图片、字体文件等),通常会设置较长时间的强缓存。
-
协商缓存能够减少不必要的资源传输量,即使服务器进行了资源验证,但返回的 304 状态响应体很小,能显著减少带宽消耗。
-
- 浏览器根据响应内容解析并渲染网页
- HTML 文档解析与构建 DOM 树
- CSS 解析与构建 CSSOM 树
- JavaScript 执行与 DOM 操作
- 构建渲染树
- 绘制与页面呈现
- 加载外部资源
网络其他常见面试题
OSI七层协议
-
OSI七层协议
-
应用层
- http https ftp smtp websocket
-
表示层
-
会话层
-
传输层
- tcp和udp
-
网络层
- IP协议 icmp互联网控制消息协议 igmp 互联网组管理协议
- 路由器 三层交换机
-
数据链路层
- 二层交换机
-
物理层
-
http状态码
-
状态码
-
1xx:信息性状态码
- 100 Continue: 表示客户端可以继续发送请求的剩余部分。
- 101 Switching Protocols: 服务器理解并愿意遵循客户端的协议切换请求。
-
2xx:成功状态码
- 200:请求成功,并且服务器返回了请求的资源(通常用于GET和POST请求)。
- 201 Created: 请求成功,并且服务器创建了新的资源(常用于POST请求)。
- 202 Accepted: 请求已接受,但尚未处理完成。
- 204 No Content: 请求成功,但服务器不需要返回任何内容。
-
3xx:重定向状态码
- 301:永久重定向。请求的资源已被永久移动到新的URL,客户端应使用新URL进行访问。
- 302:Found 临时重定向。 请求的资源临时移动到新的URL,客户端应继续使用原有的URL进行访问。。但是,HTTP/1.0 和早期的客户端可能不完全遵循这个行为,并且有时会将 POST 请求转换为 GET 请求。
- 303 See Other: 请求的资源可以在另一个URL找到,客户端应使用GET方法访问新的URL。
- 304:未修改 缓存
- 307:临时重定向但不改变method
-
4xx:客户端错误状态码
- 400:请求无效。 服务器无法理解请求的语法
- 401:当前请求需要用户验证
- 403:服务器已得到请求但拒绝执行
- 404:服务器无法根据请求找到资源
-
5xx:服务器错误状态码
- 500:服务器执行错误
- 501 Not Implemented: 服务器不支持请求的功能。
- 502:Bad Gateway网关错误 收到了上游响应但无法解析
- 503:服务器当前无法处理请求(通常是服务器过载或维护中)。
- 504:Gateway Timeout服务器作为网关或代理,未能及时从上游服务器收到响应。
- 505 HTTP Version Not Supported: 服务器不支持请求中使用的HTTP协议版本。
-
TCP和UDP的区别
- tcp面向连接 字节流,可靠/ udp无连接 面向报文,不可靠
- tcp全双工通信 /udp支持一对一一对多对一和多对多的交互通信
- tcp两端都设有缓存 用来临时存放双方通信的数据
- udp没有拥塞控制
- tcp更可靠更稳定 udp效率更高
跨域
-
跨域
-
同源策略
- 跨域问题是指在浏览器中执行的前端代码,因同源策略的限制,不能向不同域(不同协议、域名、端口)的资源发起请求。
- 同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。
-
cors
- 服务器设置适当的HTTP响应头,如Access-Control-Allow-Origin,指定允许的源,Access-Control-Allow-Methods,指定允许的方法,Access-Control-Allow-Headers,指定允许的请求头等若要带cookie请求:前后端都需要设置。
-
jsonp
- 通过动态创建script,再请求一个带参网址实现跨域通信
- jsonp缺点:只能实现get一种请求
- JSONP是一种通过
-
nginx
-
在nginx服务器上配置跨域响应头,实现跨域访问
- location /api/ { proxy_pass example.com; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'Authorization, Content-Type'; }
-
-
反向代理
- 通过在同域服务器上设置反向代理,将跨域请求代理到目标服务器,从而实现跨域访问。
-
nodejs 中间件代理跨域
- 使用http-proxy-middleware或webpack-dev-server进行配置
-
跨域资源嵌入
-
iframe+form
- 可以实现发送post请求
-
利用HTML标签(如
<script>、<img>、<iframe>)的天然跨域特性,通过加载这些资源进行数据传输
-
-