http详解
http 1.0
- 简单、灵活、易扩展、跨平台
- 基本格式:header+body
- header、status 都可以自定义
- https = http + tls/ssl
- 无状态: 服务器不会记录请求的状态
- 默认关闭
keepalive
,每次请求都建立一次tcp连接,服务器处理后立即断开tcp连接
http1.0有队头阻塞, 即没收到第一个请求对应的响应 就不能发送第二个请求
http 1.1
- 默认
keepalive|长连接
流水线模式
基于长连接,但是默认关闭
流水线模式解决了请求阻塞,不用等待前一个请求收到响应就可以发送下一个请求
但是对于响应队头阻塞没有解决。例如,服务器依次收到A和B,但是先完成了B却需要等待A完成先发送A。
keepalive的缺点
keepalive会保持tcp连接一段时间,如果服务器要响应大量不同用户一次性的请求,会造成服务器同时保活多个tcp连接
http 2.0
- 二进制格式: 把传输消息分成更小的帧,并使用二进制格式编码。头部和数据体都是二进制格式
- 并发传输:引入Stream概念,每个请求分配到唯一的StreamID,多个Stream复用一条Tcp连接。每个Stream的帧之间是有序的,不同stream的帧是可以乱序的。
- 首部压缩:减小首部大小。先给对方一份 首部各字段和对应值 的编码表,之后首部只需要填入对应编码就可以。
- 服务端推送: 收到用户的请求后,预测用户可能会请求其他资源,主动将这些资源发送给客户端。
解决了响应队头阻塞
但是没有解决tcp层面的队头阻塞
tcp的队头阻塞
多个Stream共用一个Tcp连接,即共用一个滑动窗口。那么当某个前面的stream的某个帧丢失,tcp协议规定必须按顺序读取,所以此时后面的stream全部被阻塞。
http 3.0
回顾http1.1 未解决响应队头阻塞
回顾http2.0 未解决tcp层次的队头阻塞。
所以http3.0采用 UDP + QUIC
- UDP:
- 无序
- 不可靠
- QUIC:
- 无队头阻塞
- 更快建立连接
- 连接迁移
- 无队头阻塞?
也有类似Stream与多路复用的概念,可以在同一条连接上并发传输多个Stream。当某个Stream丢包只阻塞这个Stream不影响其他Stream - 更快的建立连接
QUIC握手整合了TLS握手 - 连接迁移
http2.0采用TCP四元组来标识一个连接,当用户切换网络就要重新建立连接。
http3.0采用连接ID来标识,只要还有TLS密钥就可以无缝连接TCP四元组:(源IP+源端口+目的IP+目的端口)
轮询
先思考一个场景,服务器需要主动给用户发送请求,而http貌似只能由用户发起请求,服务器在响应该请求
要解决这个痛点,有两种办法
- 定时轮询: 前端定时发送请求给服务器
- 例如:扫码登录
- 长轮询: 设定一个时间比较长的超时时间,服务器收到请求后,先不响应,而是等待用户完成扫码操作,再响应。
这种简单的请求可以用如上方法,但是如果是游戏场景呢?
websocket解决了,全双工。
http1.1 半双工
http中谁主动断开tcp连接?
两方都可以,但是客户端主动比较好。因为主动断开方最后需要等待2msl时间,会占用资源
如果响应头包含 content-length
,则客户端知道什么时候接收完毕,客户端主动断开。
否则则服务端断开。
缓存
流程:
- 第一次请求后缓存response的资源和header,并在下一次请求同一资源时
- 根据expires和cache-control判断是否命中强缓存,如果命中则不再发起真实请求,但是状态码返回200.
- 未命中强缓存,则发起请求 .
- 服务器根据请求头的IF-Modified-Since 或 IF-None-Match , 他们的值分别表示 Last-Modified 缓存文件最晚一次修改时期,Etag 资源唯一标识(一般是hash) , 来判断缓存是否命。如果命中,服务器响应状态码为304。
- 未命中:浏览器发送资源以及新的header信息。
强制缓存
- 第一次响应后,响应头的
Expires
和Cache-Control
被保存起来- Expires: 资源过期日期。
- Cache-Control:
- max-age: 资源有效时长, 结合响应头的
Date
算出资源过期时间。 - no-cache:使用协商缓存策略。
- 优先级高于Expires
- max-age: 资源有效时长, 结合响应头的
- 如果命中,则使用本地资源。
- 如果未命中,则走协商缓存策略。
协商缓存
- 协商缓存由服务器决定资源是否可用
- 主要涉及到两对属性, 第一次响应头里的
last-Modified
或Etag
以及 后续请求头里的If-Modified-Since
或If-None-Match
,它们的值对应相等。 - 第二次请求时,请求头带上
If-Modified-Since
或If-None-Match
,服务器通过这两个属性判断资源是否变化,从而判断资源是否可用。- 如果资源不可用(更新了),则返回200,和最新资源以及新的
last-Modified
或Etag
- 如果资源可用(不变),则返回304,表示直接从缓存里拿资源
- 如果资源不可用(更新了),则返回200,和最新资源以及新的
tcp粘包
首先tcp是面向字节流的,在发送数据时需要把数据分成一个个报文
报文有两种情况:
- 大于等于mss(最小报文长度)—— 直接发送
- 小于mss —— 等待以下一个报文一起发送
可能出现如下情况,就是粘包
1 | mss1.1 ===> 发送 |