HTTP 是啥
HTTP 是一种在 两个设备 间,用于传输文字、图片、音频等 超文本内容 的协议
常见状态码
- 200
- 304
- 403
- 404
- 500
- 502
常见字段
- Host
- Content-Length
- Content-Type
- Content-Encoding
GET 与 POST 都是安全和幂等的吗?
一般来说,GET 是安全和幂等的,按照规范,GET 请求仅仅是请求 Server 的资源,不会修改 Server 的数据
而 POST 不是安全和幂等的,按照规范每一次的 POST 请求,都有可能修改 Server 的资源
但是,这都不是绝对的,可以不遵守规范,发送 GET 请求,也可以修改 Server 的资源
HTTP Cache
实现方式
HTTP 的缓存有两种实现方式:
- 强制缓存
- 协商缓存
==强制缓存==
强制缓存 是利用响应报文中的:
- Cache-Control
- Expires
来启用的,且 Cache-Control 优先级更高(因为更加控制精细)
当浏览器判断缓存的数据没有过期,就 不会 向 Server 请求这个资源,而是直接使用缓存
因此,强制缓存的 决定权是在浏览器
==协商缓存==
协商缓存 是利用响应报文中的:
- ETag
- Last-Modified
来启用的
当浏览器判断缓存过期后,如果过期的响应报文包含 ETag 或者 Last-Modified 字段,就会向 Server 发起请求,由 Server 判断资源是否过期
- 如果没有过期,Server 返回 304,客户端可以继续使用「过期」的缓存
- 否则,返回 200,Body 包含请求的数据
图解如下:
HTTP/1.1 特性
优点
- 简单
- 灵活
- 易扩展
- 跨平台
缺点
- 明文传输,不安全
- 无状态(双刃剑),需要状态信息,需要带上 Cookie 或者 Session 头
性能
相较于 HTTP/1,1.1 版本支持了长连接,可以复用 TCP 连接,不用每次请求都建立一次 TCP 连接,效率更高
但是,1.1 版本存在 队头阻塞 的问题
队头阻塞是指:虽然 1.1 版本可以复用 TCP 连接,但是如果单个请求的响应很慢,那么后面的请求也会被阻塞(因为是 串行 请求的)
![]()
HTTPS
与 HTTP 的区别?
HTTP 是明文传输,而 HTTPS 是密文传输
如何实现加密?
HTTPS 采取 混合加密 的方式保证数据的安全传输
两种加密方式:
- 对称加密:双方密钥一致
- 非对称加密:公钥 + 私钥
建立 HTTPS 的大致步骤
- 在 TLS 握手时,采取的是非对称加密
- 在数据传输时,采取的是对称加密
由于 HTTPS 采取了两种方式,因此叫做混合加密
非对称加密
- 私钥加密,公钥解密,保证数据不被冒充
- 公钥加密,私钥解密,保证数据不被篡改
但是,公钥也可能被伪造,因此,还需要有效 证书
客户端可以判断证书是否可信,如果可信,可以在证书中找到 Server 的公钥
TLS(基于 RSA)握手的详细步骤
握手后,后续通信都使用 Session Key 进行对称加密了
ECDHE 算法
前面提到的基于 RSA 算法的 TLS,仍存在安全性问题
因为 Server 的 私钥是一直不变 的,如果泄漏,那之前捕获的所有数据都可以被破解
ECDHE 算法就是来解决这个问题的
核心思想:双方的私钥都是随机生成的
- 双方事先确定好使用哪种椭圆曲线,和曲线上的基点 G,这两个参数都是公开的;
- Client 生成一个私钥,记为 p0,与基点相乘,得到公钥 q0
- Server 生成一个私钥,记为 p1,与基点相乘,得到公钥 q1
- 双方交换公钥
- 由于椭圆满足交换律(x1y2 = x2y1),因此,双方可以得到相同的 Session Key(p0q1、p1q0)
由于每次的私钥都不同,因此 ECDHE 安全性更高,即使私钥被破解(很困难),也只会影响单次通信的安全性
TLS(基于 ECDHE)握手详细步骤
- 客户端生成一个随机数 A,发送自己支持的加密方式
- 服务器确认加密方式,并生成一个随机数 B,一并发送给 Client
- 服务器发送证书
- 服务器生成一个私钥 P0,并发送选择的椭圆曲线、计算出的公钥 Q0
- 客户端验证证书
- 客户端生成一个私钥 P1,并将公钥发送给 Server
- 客户端计算 SessionKey(A + B + P1Q0)
- 服务器计算 SessionKey(A + B + P0Q1)
为了更安全,双方没有使用 P1Q0(ECDHE 计算出的共享密钥)作为会话密钥,而是再加上两个随机数
HTTPS 是否绝对安全?
场景是这样的:用户连上了一个「假基站」,将用户的请求转发到中间人服务器上,由中间人服务器转发用户请求给服务器
- 对于用户来说,用户对中间人服务器是无感的
- 对中间人服务器来说,它就相当于原来的客户端
因此中间人服务器当然可以解析出用户的请求信息,也可以解析服务器的响应信息
但前提是:用户信任了中间人服务器的 CA 证书!
一般来说,即使是连上了中间人的服务器,也会因为请求的 URL 与中间人服务器提供证书中的信息不一致而导致请求被 block 掉
所以,目前来说,HTTPS 是可以保证安全的,只要用户不作死
HTTP/1.1、HTTP/2、HTTP/3 的演变
HTTP/2 做了什么优化?
- 头部压缩
- 二进制格式
- 支持并发连接
- 服务器推送
注意:
虽然 HTTP/2 支持并发连接,但是,仍然存在「队头阻塞」的问题
假设浏览器使用 HTTP/2 协议发出了若干个并发请求
由于 TCP 协议的重传机制,当队头的响应报文的某一段丢失了,会等待服务器重传以后,才会将剩余的数据返回给应用
HTTP/3 做了什么优化?
为了解决队头阻塞的问题,以及避免建立冗杂的 TCP 连接和 TLS 握手,HTTP/3 使用了基于 UDP 的 QUIC 协议
不同于 TCP 的 IP + Port 的形式,QUIC 使用连接 ID 区分不同的连接
QUIC 的优点:
- 无队头阻塞
- 连接速度快
- 支持连接迁移(如 WLAN 切换到 5G,不需要重新建立连接)
HTTP/1.1 如何优化?
核心是减少 HTTP 请求数
- 建立缓存(前面提到过)
- 使用代理服务器处理重定向,减少 HTTP 请求数
- 懒加载
- 将多个小的资源合并成一个大的资源
- 压缩
HTTPS 如何优化?
- 硬件优化
- 软件优化:升级 Linux 版本,openssl 版本
- 协议优化:
- 使用 ECDHE 算法,而不是 RSA(ECDHE 支持「抢跑」三次握手结束后,客户端就可以发送消息 )
- 升级 TLS 版本到 1.3,1 RTT 即可握手
- 证书优化:
- 使用 ECDSA 证书,因为相同安全性下,密钥更短
- 缓存证书响应结果,避免频繁访问 CA
- 会话复用:如果 HTTPS 要重连,可以复用上一次的 SessionKey
常见复用技术:SessionID、Session Ticket 但无法保证前向安全,有「重放攻击」风险,需要设置 SessionKey 的合理过期时间
既然有 HTTP,为啥还要 RPC?
事实上,RPC 在 80 年代就有了,而 HTTP 是在 90 年代才流行起来的
所以,更准确的来说,应该是:“既然有了 RPC,为啥还要 HTTP?”
面向对象不同
HTTP 基于 C/S 架构,RPC 基于 B/S 架构
从使用目的来说,HTTP 的目的是 提供一个通用的协议 ,大家都可以用,通用型强
而 RPC,严格来说,不是一种协议,目的是 希望程序员可以想调用本地方法一样,去调用远端方法
所以,一般对外,使用 HTTP 协议,而内部的集群微服务间通信,使用 RPC
性能因素
相较于 HTTP/1.1,RPC 的性能会更好,RPC 的实现,不需要包含 HTTP 那么长的首部信息,对象序列化的时候,也可以不使用 json,而是 protobuf,更精简
而服务之间的相互调用,就符合 RPC 的场景,不需要这么多首部信息,因此,内部的集群微服务间通信,使用 RPC
其他
事实上,既然有 HTTP,为啥还要 RPC? 这个问题本身就不准确,HTTP 与 RPC 本身就可以是同时存在的,而不是互斥的,有各自的使用场景。甚至,gRPC 底层实现就是基于 HTTP/2.0 的
WebSocket
假设要实现一个 二维码登录 功能,如果使用 HTTP/1.1,怎么做?
作为前端,是不知道用户是否已经扫码,也不知道扫码结果
方法一:定时轮询
客户端每隔 1 ~ 2s 向服务器请求数据,如果服务器响应登录成功或失败,停止轮询
这种方式对于用户来说,可能会有一定延迟,如果客户端刚刚发出查询请求用户就扫码,会感知到明显延迟
方法二:长轮询
一般来说,客户端发起 HTTP 请求后,如果 Server 超过 3s 没应答,认为超时
但长轮询不同,每次 HTTP 请求会持续较场时间(如 30s),在请求时间内,如果用户扫码成功,服务器可以立即响应给客户端,用户体验比较好
但无论是定时轮询还是长轮询,本质都是向服务器「拉」数据,都不太优雅
如果服务器可以在用户扫码后,立即向客户端 推送 数据,客户端就不用发出多个 HTTP 请求,用户体验也会好很多
WebSocket 就是来解决 HTTP/1.1 的这个问题的
WebSocket 是一种基于 TCP 的 全双工 协议,多用于 Server 主动向客户端推送数据
如何建立?
要想建立 WebSocket 连接,需要用到 HTTP,并带上一个特殊的 header
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
含义:浏览器想升级协议,协议为 WebSocket,并带上一段 base64 编码的 string
如果服务器正好支持升级成 WebSocket 协议。就会走 WebSocket 握手流程,同时根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串,放在 HTTP 响应的 Sec-WebSocket-Accept 头里,同时带上 101 状态码,发回给浏览器。HTTP 的响应如下:
HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n
Upgrade: WebSocket\r\n
Connection: Upgrade\r\n
升级成 WebSocket 协议后,后续的通信与 HTTP 就没啥关系了
使用场景
WebSocket 适用于 服务器主动推送 数据的 实时通讯场景,如网页游戏
既然 http/2.0 支持服务器推送,那为啥还要用 websocket 协议?
需要弄清楚一点:HTTP/2 的服务器推送场景是:
当客户端请求一个页面(index.html)后,服务器可以预测接下来客户端要请求的数据(如 js、css 文件),并主动将这些数据推送给客户端
而 WebSocket 适用于需要频繁、实时交互的场景,例如聊天室、实时股票信息显示、在线游戏等。HTTP/2 的服务器推送虽然能够预先推送资源,但并不适用于实时性强的应用。