OSI 七层模型 和 TCP/IP 四层模型

DNS 域名解析
根域名 - 顶级域名 - 权威域名

浏览器缓存 - 操作系统缓存 - host 文件缓存 - DNS服务器缓存 - DNS 三级查找

URI: 协议+域名+路径

UDP. SPDY.

常用头字段

HTTP 协议规定了非常多的头部字段,实现各种各样的功能,但基本上可以分为四大类:

  1. 通用字段:在请求头和响应头里都可以出现;
  2. 请求字段:仅能出现在请求头里,进一步说明请求信息或者额外的附加条件;
  3. 响应字段:仅能出现在响应头里,补充说明响应报文的信息;
  4. 实体字段:它实际上属于通用字段,但专门描述 body 的额外信息。

常见的 HTTP 请求头
Accept:
Accept-Language:
Accept-Encoding:
Referer:
Host:
Cache-Control:
User-Agent”

常见的 HTTP 响应头

http 的特点

  1. 无状态
  2. 灵活可扩展
  3. 请求应答的方式
  4. 基于tcp协议是可靠的
  5. 应用层协议,可以支持很多合适的传输

http的优缺点

  1. 易扩展
  2. 环境生态成熟
  3. 明文传输 方便分析 但容易被拦截
  4. 无状态 方便负载均衡 但每次需要单独的校验身份
  5. 请求应答 可靠 但性能有影响 不够快

大文件传输

1.分块传输
请求头字段:Transfer-Encoding: chunked

2.知道文件总大小 Content-length:
范围请求 响应状态码必须是 206
客户端请求:Range: bytes=0-99( 请求头 Range 是 HTTP 范围请求的专用字段,格式是“bytes=x-y” )

服务器: 要添加一个响应头字段Content-Range,告诉片段的实际偏移量和资源的总大小,格式是“bytes x-y/length”

服务端返回:Accept-Ranges: bytes

断点续传要点:

不仅看视频的拖拽进度需要范围请求,常用的下载工具里的多段下载、断点续传也是基于它实现的,要点是:

  1. 先发个 HEAD,看服务器是否支持范围请求,同时获取文件的大小;
  2. 开 N 个线程,每个线程使用 Range 字段划分出各自负责下载的片段,发请求传输数据;
  3. 下载意外中断也不怕,不必重头再来一遍,只要根据上次的下载记录,用 Range 请求剩下的那一部分就可以了。

Nginx配置

gzip on

  1. 使用“keepalive_timeout”指令,设置长连接的超时时间,如果在一段时间内连接上没有任何数据收发就主动断开连接,避免空闲连接占用系统资源。
  2. 使用“keepalive_requests”指令,设置长连接上可发送的最大请求次数。比如设置成 1000,那么当 Nginx 在这个连接上处理了 1000 个请求后,也会主动断开连接。

队头阻塞”问题会导致性能下降,可以用“并发连接”和“域名分片”技术缓解。

利用HTTP 的长连接特性对服务器发起大量请求,导致服务器最终资源拒绝服务 这就是常说的DDoS攻击

Connection 字段还有一个取值:”Connection: Upgrade”,配和状态码101 表示协议升级,例如从HTTP 切换到 WebSocket

重定向

301
302
Location 字段

Cookie

为了保护 Cookie,还要给它设置有效期、作用域等属性,常用的有 Max-Age、Expires、Domain、Path HttpOnly 等

浏览器缓存

协商缓存
Cache-control: max-age=200 expire=时间

条件缓存
If-Modify-since: 时间
last-modify: 时间

ETG: ‘25456451’
If-None-Match: ‘25456451’

304 命中缓存
HTTP 协议 - 图1

HTTP 协议 - 图2

代理服务器

Via 代替自己的身份

  1. 专门的“代理协议”可以在不改动原始报文的情况下传递客户端的真实 IP。
  2. 如果想要知道客户端的真实 IP 地址,可以使用字段“X-Forwarded-For”和“X-Real-IP”;

反向代理中使用的负载均衡算法

  1. 轮询是upstream的默认分配方式
  2. 轮询的加强版 即可指定轮询比率 weight和访问几率成正比
  3. .ip_hash 每个请求按照访问ip (即Nginx的前置服务器或客户端IP)的hash结果分配,这样每个访客会固定访问一个后端服务器,可以解决session(会话)一致问题
  4. fair 公平的按照后端服务器的响应时间(rt) 来分配请求 ,响应时间短即rt小的后端服务器优先分配请求
  5. url_hash 与ip_hash类似,但是按照访问url的hash结果来分配请求,使得每个url定向到同一个后端服务,主要用于后端服务器为缓存的场景下

代理缓存

4 种服务器端的“Cache-Control”属性:max-age、no_store、no_cache 和 must-revalidate

HTTPS

只有同时具备了
机密性、完整性、身份认证、不可否认这四个特性,
通信双方的利益才能有保障,才能算得上是真正的安全

SSL/TLS

密码套件,协商选定的是“ECDHE-RSA-AES256-GCM-SHA384”
TLS 的密码套件命名非常规范,格式很固定。基本的形式是“密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法”
握手时使用 ECDHE 算法进行密钥交换,用 RSA 签名和身份认证,握手后的通信使用 AES 对称算法,密钥长度 256 位,分组模式是 GCM,摘要算法 SHA384 用于消息认证和产生随机数

机密性由对称加密AES保证,完整性由SHA384摘要算法保证,身份认证和不可否认由RSA非对称加密保证

可以得到 TLS 密码套件中定义的对称加密算法
比如,AES128-GCM,意思是密钥长度为 128 位的 AES 算法,使用的分组模式是 GCM;

非对称加密算法的设计要比对称算法难得多,在 TLS 里只有很少的几种,比如 DH、DSA、RSA、ECC 等。
RSA 可能是其中最著名的一个,几乎可以说是非对称加密的代名词

这就是现在 TLS 里使用的混合加密方式,其实说穿了也很简单:
在通信刚开始的时候使用非对称算法,比如 RSA、ECDHE,首先解决密钥交换的问题。
然后用随机数产生对称算法使用的“会话密钥”(session key),再用公钥加密。因为会话密钥很短,通常只有 16 字节或 32 字节,所以慢一点也无所谓。
对方拿到密文后用私钥解密,取出会话密钥。这样,双方就实现了对称密钥的安全交换,后续就不再使用非对称加密,全都使用对称加密。

TLS 1.2 密钥交换算法ECDHE

HTTP 协议 - 图3
`

TLS 1.2 密钥交换算法RSA

HTTP 协议 - 图4

TLS 1.3密钥交换算法ECDHE

HTTP 协议 - 图5

HTTP 协议 - 图6

所有加密算法:
非对称加密:ECDHE、
对称加密:AES、ChaCha20、
散列加密:SHA-2

  1. TLS1.3 也简化了握手过程,完全握手只需要一个消息往返,提升了性能。

HTTPS 的优化

响应头加 HSTS指令 (只能用HTTPS)
add_header Strict-Transport-Security max-age=15768000;

CSP(Content Security Policy)的各种指令和标签来配置安全策略
HTTP 协议 - 图7

HTTP2

HTTP2 实际上是建立在 TCP 和 TLS 协议之上的,所以会分别进行一次 TCP 握手和 TLS 握手
TLS 握手之后客户端必须发送一个请求前言 (connection preface), 用来确认建立 HTTPS/2 连接
这个“连接前言”是标准的 HTTP/1 请求报文,使用纯文本的 ASCII 码格式,请求方法是特别注册的一个关键字
“PRI”,全文只有 24 个字节
HTTP/2 请求
HTTP 协议 - 图8

伪头字段
为了与“真头字段”区分开来,这些“伪头字段”会在名字前加一个“:”,比如“:authority” “:method” “:status”,分别表示的是域名、请求方法和状态码。
HTTP 协议 - 图9
http 2 帧
HTTP 协议 - 图10

性能优化
头部压缩:
HPACK 算法 在客户端和服务端建立字典,通过索引表示重复的字符串,还釆用哈夫曼编码来压缩整数和字符串,可以达到 50%~90% 的高压缩率

二进制格式
它把 TCP 协议的部分特性挪到了应用层,把原来的“Header+Body”的消息“打散”为数个小片的二进制“帧”(Frame),用“HEADERS”帧存放头数据、“DATA”帧存放实体数据。

Stream 流式传输
解决队头阻塞,多路服用

HTTP/3
QUIC 就选定了 UDP,在它之上把 TCP 的那一套连接管理、拥塞窗口、流量控制等“搬”了过来,“去其糟粕,取其精华”,打造出了一个全新的可靠传输协议,可以认为是“新时代的 TCP”。

Nginx 服务器

Nginx 的 HTTP 处理有四大类模块:

  1. handler 模块:直接处理 HTTP 请求;
  2. filter 模块:不直接处理请求,而是加工过滤响应报文;
  3. upstream 模块:实现反向代理功能,转发请求到其他服务器;
  4. balance 模块:实现反向代理时的负载均衡算法。

  5. Nginx 是一个高性能的 Web 服务器,它非常的轻量级,消耗的 CPU、内存很少;

  6. Nginx 采用“master/workers”进程池架构,不使用多线程,消除了进程、线程切换的成本;
  7. Nginx 基于 epoll 实现了“I/O 多路复用”,不会阻塞,所以性能很高;
  8. Nginx 使用了“职责链”模式,多个模块分工合作,自由组合,以流水线的方式处理 HTTP 请求。

Websocket

WebSocket 的握手是一个标准的 HTTP GET 请求,但要带上两个协议升级的专用头字段:

  • “Connection: Upgrade”,表示要求协议“升级”;
  • “Upgrade: websocket”,表示要“升级”成 WebSocket 协议。
  • Sec-WebSocket-Key:一个 Base64 编码的 16 字节随机数,作为简单的认证密钥;
  • Sec-WebSocket-Version:协议的版本号,当前必须是 13。

看到上面的四个字段,就知道这不是一个普通的 GET 请求,而是 WebSocket 的升级请求,于是就不走普通的 HTTP 处理流程,而是构造一个特殊的“101 Switching Protocols”响应报文,通知客户端,接下来就不用 HTTP 了,全改用 WebSocket 协议通信。

WebSocket 的握手响应报文也是有特殊格式的,要用字段“Sec-WebSocket-Accept”验证客户端请求报文,同样也是为了防止误连接。

具体的做法是把请求头里“Sec-WebSocket-Key”的值,加上一个专用的 UUID “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,再计算 SHA-1 摘要。

客户端收到响应报文,就可以用同样的算法,比对值是否相等,如果相等,就说明返回的报文确实是刚才握手时连接的服务器,认证成功。
握手完成,后续传输的数据就不再是 HTTP 报文,而是 WebSocket 格式的二进制帧了