Skip to content

网络HTTP

Updated: at 04:12 PM

1. HTTP 常见面试题

1.1. HTTP基本概念

1.1.1. HTTP状态码

1XX 提示信息,表示目前是协议处理的中间状态

2XX 成功处理请求

1. 200 OK 一切正常
1. 204 No Content 与200 OK相似,只是没有body数据体
1. 206 Partial Content 表示HTTP分块下载和断点续传,表示响应返回的body数据只是资源的一部分

3XX 重定向

  1. 301 永久重定向,表示请求的资源已经不存在了,需要更改新的url再次访问
  2. 302 Found 临时重定向,说明资源还在,但暂时需要另一个URL来访问。

301和302会在响应头中使用Location表示后续要跳转的URL

  1. 304 Not Modified 不具有跳转含义,表示缓存未被修改,重定向已存在的缓存文件

4XX 客户端的报文有误

  1. 400 Bad Request 报文出错
  2. 403 Forbidden 表示服务端禁止访问资源,并不是客户端请求出错
  3. 404 Not Found 表示请求资源找不到

5XX 服务器内部错误

  1. 500 Internal Server Error 服务器内部错误 笼统错误
  2. 501 Not Implement 客户端请求的功能还不支持
  3. 502 Bad Gateway 服务器作为网关或者代理返回的错误码
  4. 503 Service Unavailable 服务器当前很忙,暂时无法相应客户端

1.1.2. HTTP常见的字段

  1. Host字段(请求)

  2. Content-Length字段(响应):表明本次回应的数据长度

    HTTP使用TCP进行传输会产生粘包问题(一个用户消息分成多个TCP报文,两个消息可能同时存在于一个报文中),HTTP有两种解决办法(一个是Header,一个是body):

    (1)设置回车符,换行符作为HTTP Header的边界

    (2)通过Content-Length字段作为HTTP body的边界

  3. Connection字段(请求):

    Connection: Keep-Alive 保持长连接,HTTP1.1默认长连接。

    Connection: close关闭长连接

  4. Content-Type 字段(响应):

    告诉客户端,本次数据是什么格式

    Content-Type: text/html; Charset=utf-8
    Accept: */* 

    客户端可以接受的

  5. Content-Encoding字段(响应):

    压缩格式

    Content-Encoding: gzip
    Accept-Encoding: gzip, deflate

1.2. GET和POST

1.2.1. GET和POST都是安全和幂等的吗?

HTTP协议中:

安全是指请求方法不会破坏服务器上的资源

幂等是多次执行相同的操作,结果是相同的

RFC协议:GET方法是安全和幂等的,可以做数据缓存避免发请求,可以作为书签,可以放到nginx上。Post请求不是安全幂等的,都不能。

1.3. HTTP缓存技术

1.3.1. HTTP缓存有哪些实现方式?

强制缓存

强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。

Cache-Control:相对时间,第一次请求后服务器响应头带着,客户端将缓存起来,下一次请求前先对比是否到了时间,没到的话从缓存中取

Expires:绝对时间

协商缓存

当我们在浏览器使用开发者工具的时候,你可能会看到过某些请求的响应码是 304,这个是告诉浏览器可以使用本地缓存的资源,通常这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存

img

两种头部实现:

  1. 请求中的If-Modified-Since 字段和响应头部中的 Last-Modified 字段实现

服务器根据If-Modified-Since与Last-Modified时间比较,如果客户端本地资源被修改过了,则从服务器查询并返回200 OK,如果没有被修改过则服务器响应304走缓存。

  1. 请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段

响应中的ETag:唯一标识响应资源

请求中的If-None-Match:当资源过期了,浏览器发现响应有ETag,则再次发送请求,并将If-None-Match附上ETag,服务器依旧是对比两个ETag,决定浏览器是否走缓存。

文件Etag描述资源更准确,所以Etag优先级高

1.4. HTTP 特性

1.4.1. HTTP1.1优点

简单,扩展,跨平台

1.4.2. HTTP1.1缺点

无状态,明文传输(不安全)

无状态

好处是不需要额外资源记忆状态

坏处是关联性操作麻烦(登录->添加购物车->下单->结算->支付,这系列操作都要知道用户的身份才行)

解决方案:Cookie技术

明文传输

解决:HTTPS,引入了SSL/TLS层

1.4.3. HTTP1.1性能

相比于HTTP1.0主要性能的提升:长连接

长连接
管道网络传输

第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

管道网络传输

但是服务器必须按照接收请求的顺序发送对这些管道化请求的响应

如果服务端在处理 A 请求时耗时比较长,那么后续的请求的处理都会被阻塞住,这称为「队头堵塞」。

所以,HTTP/1.1 管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞

际上 HTTP/1.1 管道化技术不是默认开启,而且浏览器基本都没有支持。

1.5. HTTP与HTTPS

1.5.1. HTTP与HTTPS有哪些区别?

HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。

而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。

HTTP 默认端口号是 80,HTTPS 默认端口号是 443。

HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

1.5.2. HTTPS解决了HTTP的哪些问题?

解决的问题:

  1. 信息加密,链路信息不会被窃取
  2. 检验机制,信息不会被篡改
  3. 身份证书,网站是真的网站

HTTPS如何实现的:见下面

混合加密

对称加密和非对称加密结合

1.5.3. HTTPS的应用数据是如何保证完整性的?

TLS分为握手协议和记录协议两层

握手协议即四次握手过程,记录协议即对HTTP数据的加密,压缩和数据认证

img

  1. 消息分成好几个片段,并压缩
  2. 加上MAC值(hash得到的消息认证码,以及片段编码等)
  3. 加密为密文
  4. 带上类型、版本、长度等信息

1.5.4. HTTPS一定安全可靠吗?

1.6. HTTP/1.1、HTTP/2、HTTP/3演变

1.6.1. HTTP/1.1 相比于 HTTP/1.0 提高了什么性能?

HTTP1.1相比于HTTP1.0提升的性能?

  1. 长连接
  2. 管道网络传输

HTTP1.1还有什么性能瓶颈?

  1. 请求/响应头未经压缩就发送,首部越多延迟越大
  2. 每次互相发送相同的首部
  3. 服务器队头阻塞(客户端队头阻塞已解决)
  4. 没有请求优先级控制
  5. 请求只能从客户端开始,服务端只能被动响应

1.6.2. HTTP/2 做了什么优化?

HTTP2基于HTTPS

HTTP/2相比于HTTP/1.1性能上的改进:

头部压缩

HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

二进制格式

HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧(Headers Frame)和数据帧(Data Frame)

HTTP/1 与 HTTP/2

并发传输

解决响应的队首阻塞:

img

1 个 TCP 连接包含多个 Stream,Stream 区分不同的 Message,Message 对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成。Message 里包含一条或者多个 Frame,Frame 是 HTTP/2 最小单位(一个大的请求可能被拆成多个frame),以二进制压缩格式存放 HTTP/1 中的内容(头部和包体)。

不同的Stream可以乱序发送,到了客户端对同一个Stream ID的进行组装。

服务器主动推送资源

客户端和服务器双方都可以建立 Stream, Stream ID 也是有区别的,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号。

举个例子:比如,客户端通过 HTTP/1.1 请求从服务器那获取到了 HTML 文件,而 HTML 可能还需要依赖 CSS 来渲染页面,这时客户端还要再发起获取 CSS 文件的请求,需要两次消息往返。在 HTTP/2 中,客户端在访问 HTML 时,服务器可以直接主动推送 CSS 文件,减少了消息传递的次数。

HTTP2的缺陷:在HTTP层面消除了队头阻塞,但是在TCP层面没有消除

TCP层面队头阻塞问题:

HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。

img

图中发送方发送了很多个 packet,每个 packet 都有自己的序号,你可以认为是 TCP 的序列号,其中 packet 3 在网络中丢失了,即使 packet 4-6 被接收方收到后,由于内核中的 TCP 数据不是连续的,于是接收方的应用层就无法从内核中读取到,只有等到 packet 3 重传后,接收方的应用层才可以从内核中读取到数据,这就是 HTTP/2 的队头阻塞问题,是在 TCP 层面发生的。

所以,一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来

1.6.3. HTTP/3 做了哪些优化?

HTTP/1.1解决了HTTP请求的队头阻塞,没有解决HTTP响应的队头阻塞

HTTP/2解决了HTTP响应的队头阻塞,没有解决TCP队头阻塞

HTTP3为了解决TCP层面的队头阻塞,把HTTP下层的TCP改成了UDP

UDP基于QUIC协议可以实现类似TCP的可靠性传输

QUIC协议
无队头阻塞

QUIC协议在传送Stream流的时候(Stream可以看作一个请求或者响应),当某个流发生丢包了,只会阻塞该流,不会影响其他流,所以不存在队头阻塞问题。

img

更快的连接建立

原来的HTTP2是基于HTTPS,HTTPS中的TCP与TLS是分处于不同的层(传输层和表示层),所以要先TCP建立三次握手再TLS建立三次握手。而HTTPS中的QUIC协议是包含TLS的,自己的祯会携带TLS记录。

TCP HTTPS(TLS/1.3) 和 QUIC HTTPS

甚至,在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。

连接迁移

基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。

那么当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立连接。成本高。

而HTTP/3是用ID唯一标识设备的,所以成本小。

2. HTTP/1.1 如何优化

2.1. 避免HTTP发送请求

使用缓存技术,URL作为key,响应作为value。

服务器发送响应的时候会估算一个过期时间

后续如果没有过期,也可以通过协商缓存继续走缓存

2.2. 减少HTTP请求的次数

(1)减少重定向请求次数

使用代理服务器,重定向操作由代理服务器完成

(2)合并请求

多个访问小文件的请求合并成一个大的请求,减少了重复发送的 HTTP 头部

不考虑管道模式,为了防止单个请求的阻塞,所以一般浏览器会同时发起 5-6 个请求,每一个请求都是不同的 TCP 连接,那么如果合并了请求,也就会减少 TCP 连接的数量

举例:1.多个小图片合并大图片 2. webpack合并js、css 3. base64编码将图片放到url里面

(3)延迟发送请求

按需获取

2.3. 减少HTTP响应数据的大小

(1)无损压缩

gzip算法,br算法

(2)有损压缩

webP格式

3. HTTPS RSA 握手解析

3.1. RSA 握手过程

3.1.1. TLS第一次握手

  1. 客户端首先会发一个「Client Hello」消息,里面有TLS版本号,密码套件列表,Client Random

3.1.2. TLS第二次握手

  1. 服务端发送「Server Hello」,里面有服务端TLS确认的版本号,选择一个合适的密码套件,Server Random

密码套件的一个例子:Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256,格式是「密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法」,上面密钥密钥交换算法和签名算法都是RSA,对称加密算法是ASE,摘要算法是后面SHA256用于消息认证和生成随机数

  1. 然后,为了证明身份,服务端会发送「Server Certificate」给客户端,这个消息里含有数字证书

客户端验证证书的过程:

(1)证书颁发:CA使用hash算法将公钥、用途、颁发者、有效时间等打包并计算出一个值放在证书上,然后用私钥将hash值加密生成签名也放在证书上(两部分,一个hash值,一个签名)

(2)客户端验证:用相同的hash算法得到hash值H1,再通过公钥解密签名得到H2,比较H1与H2

证书链:客户端->根证书->中间证书->baidu证书

  1. 随后,服务端发了「Server Hello Done」消息

3.1.3. TLS第三次握手

客户端验证完毕,生成一个新的随机数pre-master,用服务器的RSA公钥(CA证书携带)加密。服务端用RSA私钥解密,客户端和服务端通过Client Random、Server Random和pre-master形成对称密钥。

3.1.4. TLS第四次握手

客户端发送一个「Change Cipher Spec」,把之前的信息形成摘要使用对称密钥加密发给服务端,服务端用对称密钥解密得到消息进行验证。服务端也向客户端发送一个「Change Cipher Spec」,把之前的信息形成摘要使用对称密钥加密发给客户端,客户端用对称密钥解密得到消息进行验证。

TLS四次握手完成。

3.2. RSA算法的缺陷

使用RSA密钥协商算法的最大问题是不支持前向保密

服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解

4. HTTPS ECDHE握手协议

4.1. DH和DHE算法

DH算法:通过a^i = b(modp)当P是很大质数时i特别难算,则a可以作为公钥,i作为私钥

双方都生成公钥和私钥,公钥可以公开互传,有了公钥就能解开

若服务器私钥都时固定的,那就是DH算法,但是不具有前向安全

如果每次服务器和客户端都随机生成私钥,那就是DHE,是前向安全的,但计算性能差

4.2. ECDHE算法

DHE算法基础上使用了椭圆曲线的性质

同学1有公钥A和私钥a,同学2有公钥B和私钥b,互相交换公钥

aB = abG = baG = bA知x相同,这便是对称密钥(会话密钥)

4.3. ECDHE四次握手过程

4.3.1. TLS第一次握手

客户端「Client Hello」,TLS版本号+密码套件列表+Client Random

4.3.2. TLS第二次握手

服务端「Server Hello」,

  1. TLS版本号确认+密码套件+Server Random

密码套件示例:「 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384」

密钥协商算法使用ECDHE,签名算法还是RSA

  1. 颁发证书「Certificate

这里的证书验证算法还是RSA(即证书上的签名还是需要客户端通过RSA公钥解密)

  1. Server Key Exchange

生成随机私钥自己留着,通过椭圆基准点G计算公钥发给客户端

  1. Server Hello Done」消息

4.3.3. TLS第三次握手

认证证书之后,发送「Client Key Exchange」,自己留一个私钥,根据G计算公钥发给服务端

此时双方通过Client Random + Server Random + x(ECDHE计算出来的共享密钥)得到对称密钥

4.3.4. TLS第四次握手

客户端和服务端互发「Change Cipher Spec」以及对称密钥加密后得摘要给对方解密

5. HTTPS 如何优化

5.1. HTTPS性能损耗

  1. 增加TLS握手,最多2RTT
  2. 握手后所有消息要加密解密

5.2. 硬件优化

特定CPU支持加密算法

5.3. 软件优化

5.4. 协议优化

选择高效算法:ECDHE而不是RSA

选择好的椭圆曲线: x25519 曲线

选择对称加密算法:ASE_128_GCM

TLS升级:TLS1.3只需要1个RTT

5.5. 证书优化

ECDSA证书比RAS证书大小要小

证书验证

5.6. 会话复用

5.6.1. Session ID

客户端和服务器首次 TLS 握手连接后,双方会在内存缓存会话密钥,并用唯一的 Session ID 来标识,Session ID 和会话密钥相当于 key-value 的关系。

当客户端再次连接时,hello 消息里会带上 Session ID,服务器收到后就会从内存找,如果找到就直接用该会话密钥恢复会话状态,跳过其余的过程,只用一个消息往返就可以建立安全通信。当然为了安全性,内存中的会话密钥会定期失效。

缺点:

  1. 服务器压力大

  2. 负载均衡,不一定命中同一台服务器

5.6.2. Session Ticket

缓存工作交给客户端

客户端与服务器首次建立连接时,服务器会加密「会话密钥」作为 Ticket 发给客户端,交给客户端缓存该 Ticket。

客户端再次连接服务器时,客户端会发送 Ticket,服务器解密后就可以获取上一次的会话密钥,然后验证有效期,如果没问题,就可以恢复会话了,开始加密通信。

5.6.3. Pre-shared Key

6. RPC协议

都是应用层协议,与HTTP的区别:

  1. RPC支持长连接,一般都会有个连接池(go的网络库的HTTP也有连接池)
  2. HTTP采用JSON序列化结构体,而RPC由于定制化更高,可以采用Protobuf这样的协议序列化,体积更小,性能更好

7. WebSocket协议

双方都可以主动向对方发数据,全双工