Skip to content

Latest commit

 

History

History
357 lines (232 loc) · 20.1 KB

Http面试题.md

File metadata and controls

357 lines (232 loc) · 20.1 KB

URI URL 和 URN

URI(Uniform Resource Identifier) 统一资源标志符 URL(Uniform Resource Locator) 统一资源定位器 URN(Uniform Resource Name) 永久统一资源定位符

URL 和 URN 是 URI 的子集,URI 包含 URL 和 URN。

URL 和 URN 的区别:

  • URL 访问某一资源,如果资源已经搬迁了,还访问旧的 URL 就会报 404
  • URN 访问某一资源,即使资源已经搬迁了,还能能访问到新资源所在的地址

HTTP 客户端

  • 浏览器:浏览器是一个 http 的客户端,但是它的功能不止于此,它还可以将请求回来的资源进行解析渲染
  • curl

http 和 https 的区别

  • http传输的数据是未加密的,也就是明文的,不安全;https 是 http + ssl,ssl 协议对 http 协议传输的数据进行加密,也就是说 https 可以对数据进行加密和身份验证更安全
  • http的默认端口是80,https的默认端口是443
  • http是无状态的,https可以进行身份认证
  • https需要申请证书,需要一定的费用

https是如何加密数据的?

  1. 客户端使用 https 的 url 访问服务器,需要与服务器建立 ssl 连接
  2. 服务器会把证书信息(包含公钥)发送给客户端
  3. 客户端和服务器协商 ssl 连接的安全等级,使用对称加密生成会话秘钥
  4. 客户端使用公钥对会话秘钥进行非对称加密,发送给服务器
  5. 服务器利用私钥解密出会话秘钥
  6. 服务器利用会话秘钥加密数据与客户端进行信息传递

https数据加密后可以保证不被劫持,如何保证数据没有被篡改呢?

  1. 服务器利用 hash 算法对原数据进行处理,生成摘要信息,并用私钥加密摘要信息(数字签名)
  2. 服务器把加密后的摘要信息和原数据一起发送给客户端
  3. 客户端使用公钥解密出摘要信息
  4. 客户端利用 hash 算法对原数据进行处理,生成摘要信息
  5. 客户端比对两个摘要信息,如果一直,则数据没有被篡改

https保证数据安全的前提都是建立在公钥上的,如何保证公钥是没有被篡改的呢?

  1. 首先浏览器读取出证书中的证书所有者和有效期等信息一一验证
  2. 浏览器开始查找操作系统中已内置的受信任的证书发布机构,与浏览器发送过来的证书颁发者进行比对,来校验证书是否为合法机构发布的
  3. 如果找不到,浏览器会报错,说服务器发来的证书不安全;如果找到,取出操作系统中颁发者证书的公钥,对服务器发来的证书中的数字签名进行解密,得到摘要信息
  4. 浏览器使用相同的 hash 算法,对服务器发来的证书内容进行处理,生成摘要信息
  5. 比对两个摘要信息,如果一致,则服务器发来的证书是合法的

https的缺点是什么?

  • https 握手阶段耗时较长,会增加页面渲染时间
  • https 缓存不如 http 高效,会增加额外的数据开销
  • ssl 证书需要一定的费用
  • ssl 证书需要绑定IP,同一个 IP 不能绑定多个域名

CA证书包含哪些信息?

  • 证书发布机构CA
  • 有效期
  • 公钥
  • 证书所有者
  • 签名

使用 https 是否用户的登录密码就可以不用加密了呢?为什么?

用户的登录密码还是要加密的。因为 https 通信中间掺杂着许多代理(客户端代理、服务端代理),通过代理就能监控 https 明文数据,从而能过获取到用户未加密的账号和密码

http1.0 http1.1 http2.0 的区别是什么?

http1.1

  • 缓存处理:HTTP1.0 主要使用 Expires、Last-modified,HTTP1.1 主要使用 Cache-Control、Etag
  • 带宽优化及网络连接的使用:HTTP1.1 支持断点续传,即返回状态码 206(Partial Content)
  • 错误通知的管理:在 HTTP1.1 中新增了 24 个错误状态响应码,如409(Conflict)表示请求的资源与资源当前的状态冲突了;410(Gone)表示服务器上的某个资源被永久删除了
  • Host头处理:在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,在请求消息的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个 IP 地址。HTTP1.1 的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误 400(Bad Request)
  • 长连接:HTTP1.1 中默认开启 Connection: keep-alive,一定程度上弥补了 HTTP1.0 每次都要创建连接的缺点

http2.0

  • 新的二进制格式:HTTP1.x 的解析是基于文本,基于文本协议的格式解析存在天然的缺陷,文本的变现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认 0 和 1 的组合,基于这种考虑,HTTP2.0 的协议解析决定采用二进制,实现方便且健壮
  • header压缩:HTTP1.x 的 header 带有大量的信息,而且每次都要重复发送,HTTP2.0 使用 encoder 来减少需要传输的 header大小,通讯双方各自 cache 一份 header fields 表,避免了重复 header 的传输,又减少了需要传输的大小
  • 服务器推送:例如我的网页有一个 style.css 的请求,在客户端收到 style.css 数据的同事,服务端会将 style.js 的文件推送给 客户端,当客户端再次尝试获取 style.js 的时候就可以直接从缓存中获取,不用再发请求了
  • 多路复用
    • HTTP/1.0 每次请求响应,建立一个 TCP 连接,用完关闭
    • HTTP/1.1 长连接,若干个请求排队串行化单线程处理,后面的请求等待前面的请求的返回才能获得执行的机会,一旦有某个请求超时,后续的请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞
    • HTTP/2.0 多路复用,多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不影响到其他连接的正常执行

http1.0 http1.1 和 http2.0 在并发请求上的主要区别是什么?

  1. http1.0

每个 TCP 连接只能发送一个请求,当服务器响应后,下一次请求需要再次建立 TCP 连接

  1. http1.1

默认采用长连接,即一个 TCP 连接发送完一个请求后,默认不会关闭 TCP 连接,下个请求还会使用这个连接(Response Header: Connection: keep-alive)

追问:如何关闭长连接呢? 服务器端设置响应头 Connection: close

管道机制:在同一个 TCP 连接里,允许多个请求同时发送,所有的数据通信是有顺序的(A, B, C),但是服务器处理请求还是一个一个来的,所以会有队头阻塞的问题。

  1. http2.0

加了全双工模式,服务器也能同时处理多个请求了,解决了队头阻塞的问题。 多路复用:没有次序概念了。 加了服务器推送功能。

http1.1 的长连接和 http2.0 的多路复用有什么区别?

  1. http1.1 同一时间一个 TCP 连接只能处理一个请求,采用一问一答的形式,上一个请求响应后才能处理下一个请求。

追问:听说 Chrome 浏览器支持最大 6 个同域请求并发,这是为什么呢? 因为 Chrome 最大支持 6 个 TCP 连接

  1. http2.0 同域名上所有请求都在单个连接上完成,单个连接上可以并行交错的进行请求和响应

为什么 http1.1 不能实现多路复用?

http2.0 是基于二进制帧的协议,而 http1.1 是基于文本分隔解析协议

http1.1 的报文结构里,服务器需要不断的读入字节,直到遇到换行符,处理的顺序是串行的

http2.0 以帧为最小单位,每个帧都会有标识自己属于哪个流,多个帧组成一个流。多路复用其实就是一个 TCP 里存在多条流

http3.0

http3.0 采用 QUIC(Quick UDP Internet Connections),快速 UDP 互联网连接。QUIC 是基于 UDP 协议的

http3.0 的两个主要特性:

  1. 线头阻塞问题解决的更为彻底
基于 TCP 的 http2.0 ,尽管在逻辑上来说,不同的流之间相互独立,不会互相影响,但在实际传输方面,数据还是要一帧一帧的发送和接收,一旦某一个流的数据有丢包,则同样会阻塞在它之后传输的数据流传输。而基于 UDP 的 QUIC 协议则可以更为彻底的解决这样的问题,让不同的流之间真正的实现相互独立传输,互不干扰。
  1. 切换网络时保持连接
当前移动端的应用环境,用户的网络可能会经常切换,比如冲办公室或家里出门,wifi 断开,网络切换为 3G 或 4G。基于 TCP 的协议,由于切换网络后,IP 会改变,因而之前的连接不可能继续保持。而基于 UDP 的 QUIC 协议,则可以内建与 TCP 中不同的连接标识方法,从而在网络完成切换之后,回复之前与服务器的连接。

http跨域和cookie跨域的区别是什么?

http跨域是因为浏览器的同源策略,这里的同源是指: 协议 + 域名 + 端口 都得一致; cookie的同源策略是: domain + path,只要求域名一致,即域名一致,协议和端口不一致也是可以共享的;另外就是 path,path 为 / 表示所有 path 都可以共享

options预检请求是什么?

浏览器在发送非简单请求时,会先向服务器发送一个 options 预检请求(增加一次http请求),以获知服务器是否允许该请求

简单请求与非简单请求

简单请求必须是 get/post/head,并且这些请求的header头只能包含一些特定的字段,并且 Content-Type 的值只能是 text/plain、multipart/form-data、application/x-www-form-urlencoded...

简单请求:

  1. 必须是 get / post / head 请求
  2. 请求头只能包含这些字段:Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width
  3. Content-Type只能是这些值:text/plain、multipart/form-data、application/x-www-form-urlencoded
  4. 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
  5. 请求中没有使用 ReadableStream 对象。

强缓存和协商缓存

强缓存 Expires(HTTP/1.0) / Cache-control(HTTP/1.1)

浏览器对于强缓存的处理:根据第一次请求资源时返回的响应头来确定的

  • Expires: 缓存过期时间,用来指定资源到期的时间(HTTP/1.0)
  • Cache-Control: cache-control: max-age=2592000 第一次拿到资源后的2592000秒内(30天),再次发送请求,读取缓存中的信息(HTTP/1.1)
  • 两者都存在的话,Cache-Control 优先级高于 Expires

cache-control的取值:

- max-age: 浏览器的缓存过期时间
- s-maxage: 代理服务器的缓存过期时间

强缓存是由服务端设置的,并且基于响应头返回给客户端,客户端浏览器接收到响应后,会自己建立缓存机制,不需前端人员写代码处理

Expires 的值是一个绝对时间的 GMT 格式的时间字符串,由于失效时间是一个绝对时间,所以当服务器与客户端之间时间偏差较大时,会导致缓存混乱

Cache-Control 的取值:

  • no-store: 直接禁止浏览器缓存数据(强缓存和协商缓存都不缓存),每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源
  • no-cache: 不使用本地缓存,需要使用协商缓存
  • immutable: 在缓存有效期内,即使用户刷新浏览器也不会向浏览器发起 http 请求
  • public: 可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器
  • private: 只能被终端用户的浏览器缓存,不允许 CDN 等中间代理服务器缓存

协商缓存 Last-Modified(HTTP/1.0) / Etag(HTTP/1.1)

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来决定是否使用缓存的过程

  1. 客户端携带获取的缓存标识发送 HTTP 请求 If-Modified-Since / If-None-Match If-Modified-Since = Last-Modified 的值,If-None-Match = Etag 的值
  2. 浏览器根据资源文件是否更新返回: + 2.1 没更新,返回 304,通知客户端读取缓存的信息 + 2.2 更新了,返回 200 及最新的资源信息,以及 Last-Modified / Etag

Etag 是什么?

Etag 是一个数据签名,唯一的,根据资源内容生成的,类似于 webpack 打包出来的 contenthash

为什么会有 Etag ?

Etag 是 HTTP/1.1 新增的,主要是为了解决几个 Last-Modified 难以解决的问题:

  1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅只是修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 get
  2. 某些文件修改非常频繁,比如在秒以下的时间内修改了,if-modified-since 能检查到的粒度是秒级的,这种修改无法判断
  3. 某些服务器不能精确的得到文件的最后修改时间

强缓存和协商缓存的区别: 协商缓存总会和服务器协商,所以协商缓存总会向浏览器发送请求

强缓存和协商缓存都是针对静态资源文件

Cookie

cookie 是在服务端通过 Set-Cookie 设置的,它是一个键值对,存储在浏览器端的,浏览器在下次发送请求的时候会自动带上 cookie。Set-Cookie 可以设置多个键值对。

cookie 的属性:

  • max-age 和 expires 设置过期时间,如果没有设置,知道页面关闭或浏览器关闭前一直有效
  • secure 只在 https 的时候发送
  • HttpOnly 浏览器无法通过 document.cookie 访问

为什么在实际应用中设置的 cookie 有效期都比较短(一般半个小时,一个小时)呢?

因为时间过长,客户端保存的 session 数据就会增大,会增加服务器的压力。

DNS解析

因为浏览器不能直接通过域名找到对应的服务器IP地址,所以需要进行 DNS 解析,查找到对应的 IP 地址进行访问。

DNS解析流程:

  1. 在浏览器中输入域名,操作系统检查浏览器缓存和本地的 hosts 文件中,是否有这个网址记录,有则从记录里面找到对应的 IP 地址,完成域名解析。
  2. 查找本地 DNS 解析器缓存中,是否有这个网址记录,有则从记录里面找到对应的 IP 地址,完成域名解析。
  3. 使用 TCP/IP 参数中设置的 DNS 服务器进行查询,如果要查询的域名包含在本地配置区域资源中,则返回解析结果,完成域名解析。
  4. 检查本地 DNS 服务器是否缓存该网址记录,有则返回解析结果,完成域名解析。
  5. 本地 DNS 服务器发送查询报文至跟根 DNS 服务器,根 DNS 服务器收到请求后,用顶级域 DNS 服务器地址进行响应。
  6. 本地 DNS 服务器发送查询道文至顶级域 DNS 服务器,顶级域 DNS 服务器收到请求后,用权威 DNS 服务器地址进行响应。
  7. 本地 DNS 服务器发送查询报文至权威 DNS 服务器,权威 DNS 服务器收到请求后,用域名的 IP 地址进行响应,完成域名解析。

三次握手

  1. 客户端通过向服务器发送一个 SYN 来创建一个主动打开,作为三次握手的一部分,客户端把这段连接的序列号 Seq 设为随机数X
  2. 服务器端应当为一个合法的 SYN 返回一个 SYN/ACK,ACK的确认码为 X+1,并且 SYN/ACK 包本身又有另一个 Seq 随机序号 Y
  3. 最后,客户端再发送一个 ACK,当服务器收到这个 ACK 的时候,就完成了三次握手,并进入连接创建状态。此时包序号被设定为收到的确认号 X+1,而响应则为 Y+1

问题:为什么是三次握手,而不是两次或者四次呢?

简单来说,就是要保证在一段有效时间内,双方收到对方的有效信息。A 发送给 B,B 回复 A,A 如果不再回复 B,B 怎么知道 A 可以收到呢

TCP 作为一种可靠传输控制协议,其核心思想:既要保证数据可靠传输,又要提高传输的效率。

四次挥手

  1. 客户端 A 发送一个 FIN,用来关闭客户端 A 到服务器 B 的数据传送
  2. 服务器 B 收到这个 FIN 后,它发回一个 ACK,确认序号为收到的序号加1
  3. 客户端 A 发送 FIN,服务器 B 是可以继续把它需要响应给客户端 A 的数据发送完,然后服务器 B 关闭与客户端 A的连接,发送一个 FIN 给客户端 A
  4. 客户端 A 发回 ACK 报文确认,并将确认序号设置为收到的序号加1

问题:为什么连接的时候是三次握手,关闭的时候却是四次挥手呢?

  • 服务器端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文
  • 但关闭连接时,当服务器端收到FIN报文后,很可能并不会立即关闭连接,所以只能先回复一个ACK报文,告诉客户端:“你发送的FIN报文我收到了”,只有等到服务器端所有的报文都发送完后,我才能发送FIN报文,因此不能一起发送,故需要四次握手

301 和 302

  • 302 临时重定向,再次刷新浏览器的时候,浏览器还是会先访问原始的路径,然后在访问重定向后的路径
  • 301 永久重定向,再次刷新浏览器的时候,浏览器会直接访问重定向后的路径,并且是从缓存中取出重定向的路径的地址,也就是说即使服务器端已经改变了地址(301后反悔),这个时候如果没有刷新浏览器的缓存,还是会去访问之前缓存的重定向后的地址。所以 301 要谨慎使用

CSP(Content-Security-Policy) 内容安全策略

作用:

  • 限制请求的资源来源
  • 报告资源获取越权

使用方式:

  • 在服务器端对响应的 header 做限制
  • 在 html 的 meta 标签上做限制

websocket 的特点

  1. 建立在 TCP 协议之上,服务器端的实现也比较容易
  2. 与 http 协议有良好的兼容性,默认端口也是 80 和 443,握手阶段采用的是 http 协议
  3. 数据格式比较轻量,性能开销小,通信高效
  4. 可以发送文本,也可以发送二进制数据
  5. 没有同源限制,客户端和任意服务器都可以通信
  6. 协议标识符是 ws,如果加密,则是 wss

websocket 实例对象的四种状态

websocket.readyState:

  • CONNECTING: 值为0,表示正在连接
  • OPEN: 值为1,表示连接成功
  • CLOSING: 值为2,表示正在关闭
  • CLOSED: 值为3,表示连接已经关闭

websocket 服务器的数据可能是文本,也可能是二进制

  1. 接收的时候判断数据的类型
ws.onmessage = function (event) {
  if (typeof event.data === 'string') {}
  // if (event.data instanceof ArrayBuffer) {}
}
  1. 指定接收的二进制数据的类型
ws.binaryType = 'blob'
ws.onmessage = function (e) {
  console.log(e.data.size)
}
// ws.binaryType = 'arrayBuffer'
// ws.onmessage = function (e) {
//   console.log(e.data.byteLength)
// }

websocket 的实现原理

websocket 是应用层第七层上的一个应用层协议,它必须依赖 http 协议进行依次握手(这是为了兼容所有的浏览器),握手成功后,数据直接从 TCP 通道传输,与 http 无关了。websocket 分为握手和数据传输阶段,即进行 http 握手 + 双工的 TCP 连接。

  1. 握手阶段
  • 客户端发送消息,请求头里还包含:

Upgrade: websocket Connection: Upgrade

这个就是 websocket 的核心了,告诉服务器,我发送的请求要用 websocket 协议。

除此之外,客户端发送消息,请求头里包含:

Sec-Websocket-Key: xxxxxxxxxxx Sec-Websocket-key 是一个 Base64 encode 的值,这是浏览器随机生成的 Sec-Websocket-Protocol: chat, superchat 是一个用户自定义的字符串,用来区分同 URL 下,不同的服务所需要的协议 Sec-Websocket-Version: 13 告诉服务器使用的 WebSocket Draft (协议版本)

  • 服务端返回消息,响应头里包含:

Upgrade: websocket Connection: Upgrade

告诉客户端,我已经切换协议啦

Sec-Websocket-Accept: xxxxxxxxx

这里需要注意的是 Sec-websocket-Accept 的计算方法:base64(hsa1(sec-websocket-key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11))

如果这个 Sec-Websocket-Accept 计算错误,浏览器会提示 Sec-Websocket-Accept dismatch,如果返回成功,Websocket 就会回调 onopen 事件

Sec-Websocket-Protocol 表示最终使用的协议