2023 年最新最全的 http 网络面试题

蚊子前端博客
发布于 2023-03-13 23:16
了解更多 http 相关相纸,更能方便我们定位问题和优化性能

有些同学可能不理解,为什么前端同学还要学习和了解 http 的相关知识?其实很多内容在我们的开发过程中都是有用到的,了解更多 http 相关的知识,更能方便我们定位问题,和优化性能。

TCP 的三次握手与四次挥手

三次握手

最开始的时候客户端和服务器都是处于 CLOSED 关闭状态。主动打开连接的为客户端,被动打开连接的是服务器。

TCP 服务器进程先创建传输控制块 TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了 LISTEN 监听状态

第一次握手 TCP 客户进程也是先创建传输控制块 TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位 SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP 客户端进程进入了 SYN-SENT 同步已发送状态

第二次握手 TCP 服务器收到请求报文后,如果同意连接,则会向客户端发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是 ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP 服务器进程进入了 SYN-RCVD 同步收到状态

第三次握手 TCP 客户端收到确认后,还要向服务器给出确认。确认报文的 ACK=1,ack=y+1,自己的序列号 seq=x+1,此时,TCP 连接建立,客户端进入 ESTABLISHED 已建立连接状态 触发三次握手

三次握手-蚊子的前端博客

主要原因:防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误

第一次握手: 客户端向服务器端发送报文 证明客户端的发送能力正常 第二次握手:服务器端接收到报文并向客户端发送报文 证明服务器端的接收能力、发送能力正常 第三次握手:客户端向服务器发送报文 证明客户端的接收能力正常

如果采用两次握手会出现以下情况: 客户端向服务器端发送的请求报文由于网络等原因滞留,未能发送到服务器端,此时连接请求报文失效,客户端会再次向服务器端发送请求报文,之后与服务器端建立连接,当连接释放后,由于网络通畅了,第一次客户端发送的请求报文又突然到达了服务器端,这条请求报文本该失效了,但此时服务器端误认为客户端又发送了一次连接请求,两次握手建立好连接,此时客户端忽略服务器端发来的确认,也不发送数据,造成不必要的错误和网络资源的浪费。

如果采用三次握手的话,就算那条失效的报文发送到服务器端,服务器端确认并向客户端发送报文,但此时客户端不会发出确认,由于客户端没有确认,由于服务器端没有接收到确认,就会知道客户端没有请求连接。

四次挥手

数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于 ESTABLISHED 状态,然后客户端主动关闭,服务器被动关闭。

第一次挥手 客户端发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为 seq=u(等于前面已经传送过来的数据的最后一个字节的序号加 1),此时,客户端进入 FIN-WAIT-1(终止等待 1)状态

第二次挥手 服务器端接收到连接释放报文后,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号 seq=v,此时,服务端就进入了 CLOSE-WAIT 关闭等待状态

第三次挥手 客户端接收到服务器端的确认请求后,客户端就会进入 FIN-WAIT-2(终止等待 2)状态,等待服务器发送连接释放报文,服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,服务器就进入了 LAST-ACK(最后确认)状态,等待客户端的确认。

第四次挥手 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是 seq=u+1,此时,客户端就进入了 TIME-WAIT(时间等待)状态,但此时 TCP 连接还未终止,必须要经过 2MSL 后(最长报文寿命),当客户端撤销相应的 TCB 后,客户端才会进入 CLOSED 关闭状态,服务器端接收到确认报文后,会立即进入 CLOSED 关闭状态,到这里 TCP 连接就断开了,四次挥手完成。

四次挥手-蚊子的前端博客

tcp 和 udp 的区别,及使用场景?

tcp 和 udp 的区别-蚊子的前端博客

tcp

TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,当应用程序采用 TCP 发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端。TCP 是面向面向字节流,虽然应用程序和 TCP 的交互是一次一个数据块(大小不等),但 TCP 把应用程序看成是一连串的无结构的字节流。TCP 有一个缓冲,当应用程序传送的数据块太长,TCP 就可以把它划分短一些再传送。

TCP 为提供可靠性传输,实行“顺序控制”或“重发控制”机制。此外还具备“流控制(流量控制)”、“拥塞控制”、提高网络利用率等众多功能。

UDP

UDP 是面向报文的,所谓面向报文,是指面向报文的传输方式是应用层交给 UDP 多长的报文,UDP 就照样发送,即一次发送一个报文。因此,应用程序必须选择合适大小的报文。若报文太长,则 IP 层需要分片,降低效率。若太短,会是 IP 太小。

UDP 是不具有可靠性的数据报协议,细微的处理它会交给上层的应用去完成。在 UDP 的情况下,虽然可以确保发送消息的大小,却不能保证消息一定会到达。因此,应用有时会根据自己的需要进行重发处理。

tcp 如何保证可靠传输?

  1. 应用数据被分割成 TCP 认为最适合发送的数据块。

  2. TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。

  3. 校验和:TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。

  4. TCP 的接收端会丢弃重复的数据。

  5. 流量控制:TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制)

  6. 拥塞控制:当网络拥塞时,减少数据的发送。

  7. ARQ 协议:也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。

  8. 超时重传:当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。

http 各个版本之间的区别?

HTTP/1.0

[特点]

  1. 任何格式的内容都可以发送。这使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件。这为互联网的大发展奠定了基础。

  2. 除了 GET 命令,还引入了 POST 命令和 HEAD 命令,丰富了浏览器与服务器的互动手段。

  3. HTTP 请求和回应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。

  4. 其他的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。

[不足]

HTTP/1.0 版的主要缺点是,每个 TCP 连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。TCP 连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0 版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。

HTTP/1.1

[特点]

  1. 引入了持久连接(persistent connection),即 TCP 连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive;

  2. 引入了管道机制(pipelining),即在同一个 TCP 连接里面,客户端可以同时发送多个请求。这样就进一步改进了 HTTP 协议的效率;

  3. 将 Content-length 字段的作用进行扩充,即声明本次回应的数据长度(一个 TCP 连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的)

  4. 采用分块传输编码,对于一些很耗时的动态操作,服务器需要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer);

  5. 1.1 版还新增了许多动词方法:PUT、PATCH、HEAD、 OPTIONS、DELETE。另外,客户端请求的头信息新增了 Host 字段,用来指定服务器的域名

[不足]

虽然 1.1 版允许复用 TCP 连接,但是同一个 TCP 连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入 CSS 代码、域名分片(domain sharding)等等。如果 HTTP 协议设计得更好一些,这些额外的工作是可以避免的。

HTTP/2.0

简单来说,HTTP/2(超文本传输协议第 2 版,最初命名为 HTTP2.0),是 HTTP 协议的第二个主要版本。HTTP/2 是 HTTP 协议自 1999 年 HTTP1.1 发布后的首个更新,主要基于 SPDY 协议。

HTTP2.0 的特点是:在不改动 HTTP 语义、方法、状态码、URI 及首部字段的情况下,大幅度提高了 web 性能。

  1. 二进制传输:在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层上,HTTP2.0 会将所有传输的信息分为更小的消息和帧,并采用二进制格式编码,其中 HTTP1.x 的首部信息会被封装到 Headers 帧,而 Request Body 则封装到 Data 帧;

  2. 多路复用:即在一个 TCP 连接中存在多个流,即可以同时发送多个请求,对端可以通过帧中的表示知道该帧属于哪个请求。在客户端,这些帧乱序发送,到对端后再根据每个帧首部的流标识符重新组装。通过该技术,可以避免 HTTP 旧版本的队头阻塞问题,极大提高传输性能;

  3. Header 压缩:在 HTTP1.0 中,我们使用文本的形式传输 header,在 header 中携带 cookie 的话,每次都需要重复传输几百到几千的字节,这着实是一笔不小的开销。在 HTTP2.0 中,我们使用了 HPACK(HTTP2 头部压缩算法)压缩格式对传输的 header 进行编码,减少了 header 的大小。并在两端维护了索引表,用于记录出现过的 header,后面在传输过程中就可以传输已经记录过的 header 的键名,对端收到数据后就可以通过键名找到对应的值。

  4. 服务器推送:服务端可以在客户端某个请求后,主动推送其他资源;

HTTP/3.0

HTTP2 协议虽然大幅提升了 HTTP/1.1 的性能,然而,基于 TCP 实现的 HTTP2 遗留下 3 个问题:

  • 有序字节流引出的队头阻塞(Head-of-line blocking),使得 HTTP2 的多路复用能力大打折扣;

  • TCP 与 TLS 叠加了握手时延,建链时长还有 1 倍的下降空间;

  • 基于 TCP 四元组确定一个连接,这种诞生于有线网络的设计,并不适合移动状态下的无线网络,这意味着 IP 地址的频繁变动会导致 TCP 连接、TLS 会话反复握手,成本高昂。

HTTP3 协议解决了这些问题:

  • HTTP3 基于 UDP 协议重新定义了连接,在 QUIC 层实现了无序、并发字节流的传输,解决了队头阻塞问题(包括基于 QPACK 解决了动态表的队头阻塞);

  • HTTP3 重新定义了 TLS 协议加密 QUIC 头部的方式,既提高了网络攻击成本,又降低了建立连接的速度(仅需 1 个 RTT 就可以同时完成建链与密钥协商);

  • HTTP3 将 Packet、QUIC Frame、HTTP3 Frame 分离,实现了连接迁移功能,降低了 5G 环境下高速移动设备的连接维护成本。

参考: https://zhuanlan.zhihu.com/p/431672713 。

https 的连接和传输过程

  1. 客户端发起请求,连接服务器 443 端口

  2. 服务端有公钥和私钥,用于非对称加密,将公钥以证书的形式发送给客户端

  3. 客户端收到后,验证证书是否合格,不合格,则 https 请求无法继续,合格,则客户端随机生成一个私钥,用于对称加密,使用公钥对客户端私钥进行非对称加密

  4. 发起第二个请求,将加密后的客户端私钥发送给服务器

  5. 服务器收到后,用服务器私钥对密文进行非对称解密,得到客户端私钥,用客户端私钥对数据进行对称加密

  6. 将对称加密的数据发给客户端,用客户端私钥进行对称解密,得到数据。整个 https 传输完成

https 的连接和传输过程-蚊子的前端博客

DNS 的查找过程

  1. 先搜索浏览器的缓存;

  2. 操作系统的缓存;

  3. 本地域名服务器的缓存;

  4. 顶级域名服务器的缓存;

  5. 根域名服务器的缓存

URL 从输入到网页显示的全过程

  1. dns 域名解析,得到实际的 ip 地址,浏览器 -- 本地 hosts -- 本地域名服务器(递归查找) -- 根域名服务器(迭代查找)

  2. 检查浏览器是否有缓存:Cache-Control 和 Expires 来检查是否命中强缓存,命中则直接取本地磁盘的 html(状态码为 200 from disk(or memory) cache,内存 or 磁盘);没有命中强缓存,则会向服务器发起请求(先进行下一步的 TCP 连接),服务器通过 Etag 和 Last-Modify 来与服务器确认返回的响应是否被更改(协商缓存),若无更改则返回状态码(304 Not Modified),浏览器取本地缓存;

  3. 建立 TCP 连接,三次握手,如果协议是 https,还需要做加密;

  4. 浏览器发送请求获取页面 html;

  5. 服务器响应 html;

  6. 浏览器解析 html;

将 html 解析成一个 DOM 树(深度遍历),将 css 解析成 css 规则树,浏览器引擎会将它们合并成渲染树。布局。绘制。

过程中,遇到 css,不会阻塞 DOM 树的解析,但会阻塞 DOM 树的渲染,并会阻塞 js 执行。

遇到 js,会阻塞 DOM 树的解析,所以 js 要放在下面或者异步加载。defer 或 async。

参考: https://www.xiabingbao.com/browser/2015/05/16/happens-type-in-url-browser.html

强缓存和协商缓存

通过复用以前获取的资源,可以显著提高网站和应用程序的性能。Web 缓存减少了等待时间和网络流量,因此减少了显示资源表示形式所需的时间。通过使用 HTTP 缓存,变得更加响应性。

通常 http 缓存分为强缓存和协商缓存。

强缓存

在浏览器加载资源时,先看看 cache-control 里的 max-age(或 expired 属性),判断数据有没有过期,如果没有直接使用该缓存,不再发送网络请求

当 max-age 和 expired 同时存在时,max-age 优先级更高。

协商缓存

根据内容最后的修改时间(Last-Modified),或者标识(ETag),来判断内容是否发生了变化,若没有变化,则告诉浏览器直接使用缓存即可,否则返回最新的内容。

协商缓存是每次都要请求服务器的,然后服务器校验是走缓存,还是下发新的内容。当可以使用客户端的缓存时,只需要返回 304 状态码即可。

参考:https://www.xiabingbao.com/post/http/http-cache-rblrrn.html

为什么会有跨域?怎么解决?

跨域的产生

协议、域名、端口,任意一个不相同时,则会产生跨域。即同源安全策略

为了安全考虑,阻止恶意的攻击,减少可能被攻击的媒介。不遵循同源规则的,不允许访问。

因为跨域限制,是浏览器进行限制的。因此后端对后端的互相请求,即使协议、域名、端口等都不一样,也是没有所谓的跨域问题的。

跨域时,后端会收到请求吗?

前端依然会发出请求,后端接口会收到请求,并正常返回,但浏览器并不会处理。然后提示存在跨域错误。

跨域的解决方案有哪些?

跨域的解决方案-蚊子的前端博客

  1. jsonp:利用 script 标签没有跨域限制的特点,通过动态生成 script 标签,指定 src 属性的方式加载跨域资源。

  2. cors:浏览器是否启用同源安全策略是根据后端响应的 Access-Control-Allow-Origin 响应头来定的,所以配置后端是最直接的一种方法,也是工作中常用的解决方案。

  3. 中间服务器代理:根据代理类型分为正向代理和反向代理。正向代理是代理服务器对客户端进行代理,为客户端收发请求,使得真实客户端对目标服务器不可见,如本地的 devServer;反向代理是代理服务器对目标服务器进行代理,为目标服务器进行收发请求,使得真实服务器对客户端不可见,如 nginx。

access-control-allow-origin

跨源资源共享标准新增了一组 HTTP 标头字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。

当把Access-Control-Allow-Origin设置为*时,即Access-Control-Allow-Origin: *,则表示该资源可以被任意外源访问。但如果需要传递 cookie 时,请不要把下面的几个属性设置为*,否则请求将会失败:

  • Access-Control-Allow-Origin:应当设置为指定的域,如:Access-Control-Allow-Origin: https://example.com;注意,这里要把协议、域名和端口都要写完整,否则跟前端不一样的话,还是会跨域;

  • Access-Control-Allow-Headers:应将其设置为标头名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type

  • Access-Control-Allow-Methods:应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET

什么是简单请求和复杂请求,为什么会有 options 类型的请求?

某些请求不会触发 CORS 预检请求,这样的请求一般称为 “简单请求” ,而会触发预检的请求则是 “复杂请求” 。

简单请求

  • 请求方式为 GET、HEAD、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;

  • 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;

  • 请求中没有使用 ReadableStream 对象。

复杂请求

  • PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH;

  • 人为设置了以下集合之外首部字段,即简单请求外的字段;

  • Content-Type 的值不属于下列之一,即 application/x-www-form-urlencoded、multipart/form-data、text/plain。

options 请求

options 请求就是预检请求,可用于检测服务器允许的 http 方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起 OPTIONS 请求,即 CORS 预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求;不支持的话,会在控制台显示错误

所以,当触发预检时,跨域请求便会发送 2 次请求。

永久重定向和临时重定向?

永久重定向

永久重定向,请求的网页已永久移动到新位置,浏览器会自动重定向到新的 url 地址。而永久重定向的连接,浏览器本地是会有缓存的,下次再遇到相同的地址时,不再请求服务器,而是直接重定向。如 http 永久重定向到 https,旧地址永久重定向到新地址。

永久重定向的状态码有 301 和 308:

  • 301 状态码表明目标资源被永久的移动到了一个新的 URI,任何未来对这个资源的引用都应该使用新的 URI。因历史原因,浏览器在实现该功能时,经常会把之前的 post 请求改成 get 请求。

  • 308 状态码与 301 的功能一样,但不会修改请求方式。

临时重定向

临时重定向,表示目标资源临时移动到了另一个 URI 上。因为是临时重定向,浏览器再次遇到之前的请求时,还是会重新请求服务器,再决定接下来的响应。如链接跳转经常使用这种方式,既能避免任意的外链跳转,也能统计链接的点击量。

临时重定向的状态码有 302, 303 和 307:

  • 302:该状态码表示目标资源临时移动到了另一个 URI 上。由于重定向是临时发生的,所以客户端在之后的请求中还应该使用原本的 URI。但因历史原因,经常会把之前的 post 请求改成 get 请求。

  • 303:常用于将 POST 请求重定向到 GET 请求。即该状态码重定向都是 GET 请求。

  • 307:与 302 的功能一样,但不会修改请求方式。

GET 请求和 POST 请求的区别

GET 和 POST 是 HTTP 中最常用的两个方法。

  • get 请求的 URL 有长度限制,而 post 请求会把参数和值放在消息体中,对数据长度没有要求。

  • get 请求会被浏览器主动 cache,而 post 不会,除非手动设置。

  • get 请求在浏览器反复的 回退/前进 操作是无害的,而 post 操作会再次提交表单请求。

  • get 请求在发送过程中会产生一个 TCP 数据包;post 在发送过程中会产生两个 TCP 数据包。对于 get 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200(返回数据);而对于 post,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)。

标签:
阅读(823)

公众号:

qrcode

微信公众号:前端小茶馆