一、网络分层与协议位置
1.1 七层、五层、四层模型对照表
三种模型在同一张表中对照(自下而上:第 1~7 行对应物理层到应用层)。
- 口诀:物数网传会表应(从下往上记)。
- 层组列:标出各层归属。
- 表中「↑ 同上」:与上一格属同一层(无独立层界)。
| 层组 | OSI 七层 | TCP/IP 五层 | TCP/IP 四层 | 对应关系 | 主要功能 | 典型协议 / 例子 | 典型设备 |
|---|---|---|---|---|---|---|---|
| 应用层 | 第 7 层 应用层 | 第 5 层 应用层 | 第 4 层 应用层 | 7、6、5 → 应用层;HTTP/HTTPS 在此层(端口 80/443,基于 TCP) | 为应用程序提供网络服务接口 | HTTP、HTTPS、FTP、SMTP、DNS、WebSocket | 主机、终端、应用网关 |
| 应用层 | 第 6 层 表示层 | ↑ 同上 | ↑ 同上 | ↑ 同上 | 数据格式转换、加解密、压缩 | SSL/TLS(部分)、JPEG、MPEG、编码 | ↑ 同上 |
| 应用层 | 第 5 层 会话层 | ↑ 同上 | ↑ 同上 | ↑ 同上 | 建立、管理、终止会话 | RPC、NetBIOS、SQL 会话 | ↑ 同上 |
| 传输层 | 第 4 层 传输层 | 第 4 层 传输层 | 第 3 层 传输层 | 4 → 传输层 | 端到端可靠/不可靠传输、端口寻址 | TCP、UDP | 主机(端设备) |
| 网络层 | 第 3 层 网络层 | 第 3 层 网络层 | 第 2 层 网际层 | 3 → 网络层/网际层 | 路由选择、逻辑寻址、分组转发 | IP、ICMP、ARP | 路由器 |
| 数据链路层 | 第 2 层 数据链路层 | 第 2 层 数据链路层 | 第 1 层 网络接口层 | 2 → 数据链路层;四层中 2、1 → 网络接口层 | 成帧、差错控制、MAC 寻址 | Ethernet、WiFi、PPP | 交换机、网桥 |
| 物理层 | 第 1 层 物理层 | 第 1 层 物理层 | ↑ 同上 | 1 → 物理层;四层中 ↑ 同上 | 比特流传输、物理接口与介质 | 双绞线、光纤、无线电 | 中继器、集线器、网卡 |
SSL/TLS 属于哪一层(常考)
- OSI 七层:通常归表示层(第 6 层)(加解密、数据格式转换);也有归会话层(第 5 层)(建立与管理安全会话)的说法。
- TCP/IP 四层/五层:无单独表示层、会话层,故归入应用层。
- 通俗记:SSL/TLS 夹在应用协议(如 HTTP)与传输层(TCP)之间——对应用层是「下面一层」的加密通道,对 TCP 是「上面一层」的 payload。
二、HTTP 概述
2.1 定义与全称
- 全称:HyperText Transfer Protocol(超文本传输协议)。
- 定义:HTTP 是应用层协议,在浏览器与服务器之间传输数据,基于 TCP(默认端口 80,HTTPS 为 443),采用请求-响应模式:客户端发请求,服务器回响应。
- 为什么用 TCP 不用 UDP(常考):HTTP 需要可靠、有序地传输完整报文(请求/响应不能丢、不能乱序);TCP 提供可靠传输、流量控制、连接管理,适合这种语义。UDP 不保证可靠与有序,适合实时、可丢的场景(如音视频),不适合 HTTP 正文。
2.2 主要特点
| 特点 | 说明 |
|---|---|
| 无状态(Stateless) | 每次请求独立,服务器不记录上次请求、不区分是否同一客户端。优点:实现简单、易水平扩展、易做负载均衡、单次失败不影响其他请求。缺点:登录态、购物车等需在应用层维护,常用 Cookie、Session 或 Token。 |
| 请求-响应(Request-Response) | 通信由客户端主动发起,一次请求对应一次响应,顺序固定。服务器不能主动向客户端推数据;若要实时推送需 WebSocket、SSE 等。 |
| 基于 TCP | 运行在 TCP 之上,保证数据可靠、有序到达;默认端口 80(HTTPS 为 443)。 |
| 明文传输 | 默认不加密,请求与响应内容可被窃听、篡改。生产环境应使用 HTTPS(在 HTTP 与 TCP 之间增加 SSL/TLS 加密)。 |
| 灵活 / 可扩展 | 支持多种请求方法(GET、POST、PUT、DELETE 等)、多种 Content-Type(JSON、表单、二进制等)和自定义头;协议本身可随版本(如 1.1、2、3)扩展而不破坏语义。 |
无状态补充:服务器不保存会话,同一用户多次请求在协议层面无关联。需要「记住用户」时,由应用自行实现,例如:
- Cookie(存客户端)
- Session(存服务端,用 SessionID 关联)
- Token(如 JWT)
2.3 请求与响应的结构
- 请求:请求行(方法 + URL + 协议版本)+ 请求头 + 空行 + 可选请求体。
- 响应:状态行(协议版本 + 状态码 + 描述)+ 响应头 + 空行 + 可选响应体。
示例(请求):
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
示例(响应):
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
<html>...</html>
2.4 版本演进与特性对照
各版本主要特性对照(— 表示无或不适用)。
| 特性 | HTTP/0.9 | HTTP/1.0 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|---|---|
| 连接 | 短连接 | 默认短连接 | 默认长连接(Keep-Alive) | 长连接 + 多路复用 | 基于 QUIC,建连更快 |
| Host 头 | — | 不要求 | 必须 | 必须 | 必须 |
| 请求头/响应头 | 无 | 有 | 有 | 有(可压缩) | 有 |
| 分块传输 | — | 不支持 | 支持(Chunked) | 支持 | 支持 |
| 缓存 | — | 多用 Expires | 多用 Cache-Control | 同 1.1 | 同 1.1 |
| 范围请求 | — | 不支持 | 支持(Range / 206) | 支持 | 支持 |
| 多路复用 | — | — | 不支持(有队头阻塞) | 支持 | 支持 |
| 头部压缩 | — | — | 无 | HPACK | QUIC 内建 |
| 二进制分帧 | — | 文本 | 文本 | 二进制帧 | 二进制 |
| 服务端推送 | — | — | 不支持 | 支持 | 支持 |
| 传输层 | TCP | TCP | TCP | TCP | QUIC(UDP) |
| 备注 | 仅 GET,已废弃 | 引入状态码、Content-Type | 当前最常用 | 多需 HTTPS | 减少队头阻塞 |
2.5 多路复用、头部压缩、二进制分帧、服务端推送(HTTP/2)
下表对版本表中出现的四项 HTTP/2 特性做简要说明。
| 概念 | 含义与作用 |
|---|---|
| 多路复用(Multiplexing) | 同一条 TCP 连接上同时收发多组请求/响应,互不阻塞。HTTP/1.1 下同连接请求串行,易队头阻塞;多路复用后请求可交错、响应可乱序,提高带宽利用、降低延迟。 |
| 头部压缩(Header Compression) | 请求/响应头重复多(如 Host、Cookie)。HTTP/2 用 HPACK 在连接上维护头表,只传差异或索引,减少重复,降低开销。 |
| 二进制分帧(Binary Framing) | HTTP/1.x 为文本;HTTP/2 将报文拆成二进制帧(含类型、流 ID 等),便于解析、与多路复用配合(按流 ID 区分请求/响应)及做流控。 |
| 服务端推送(Server Push) | 服务器可在未收到请求时主动推送可能用到的资源(如 CSS、JS),减少 RTT,加快首屏;客户端可拒绝或取消。 |
三、HTTP 请求方法
3.1 常用方法对照
从用途、幂等性、安全性、参数位置、是否可缓存、典型场景等多方面对照。幂等:多次相同请求效果一致;安全:不改变服务器状态。
| 方法 | 用途 | 幂等 | 安全 | 参数/数据位置 | 可缓存 | 典型场景与备注 |
|---|---|---|---|---|---|---|
| GET | 获取资源 | 是 | 是 | URL 查询串(?k=v&…),有长度限制,敏感信息不宜放 URL | 是 | 查询、获取页面/接口数据、下载;只读,不应改服务端状态 |
| POST | 提交/创建 | 否 | 否 | 请求体(表单、JSON、二进制等),长度通常不限 | 否 | 提交表单、创建资源、登录、文件上传;多次相同请求可能产生多条数据 |
| PUT | 全量更新 | 是 | 否 | 请求体;URL 指向具体资源(如 /users/123) | 否 | 全量替换该资源;资源不存在时可约定为创建;幂等 |
| DELETE | 删除 | 是 | 否 | 一般无 body;URL 指向要删除的资源 | 否 | 删除 URL 指定资源;常用 204 No Content;重复删除同一资源仍为幂等 |
| HEAD | 只取头 | 是 | 是 | 同 GET,无请求体 | 是 | 与 GET 相同但只返回响应头;用于检查资源存在、大小、Last-Modified/ETag,省带宽 |
| OPTIONS | 询问能力 | 是 | 是 | 通常无 body | 是 | 返回 Allow 等;常用于 CORS 预检(Access-Control-*);不修改资源 |
| PATCH | 部分更新 | 通常否 | 否 | 请求体(仅含要改的字段);URL 指向具体资源 | 否 | 只更新部分字段,不替换整份资源;是否幂等取决于服务端实现 |
GET 与 POST 对比小结
- GET:参数在 URL、可缓存、幂等且安全,适合查询。
- POST:数据在 body、不缓存、非幂等,适合提交与创建。
- 敏感数据、大数据量宜用 POST。
四、HTTP 状态码
4.1 分类概览
状态码首位数字表示类别,后两位表示具体含义。响应头与 body 由协议与实现决定,下表仅作语义说明。
| 类别 | 范围 | 含义 |
|---|---|---|
| 1xx | 100–199 | 信息性:请求已接收,继续处理 |
| 2xx | 200–299 | 成功:请求已被成功处理 |
| 3xx | 300–399 | 重定向:需进一步操作(换 URL 或使用缓存) |
| 4xx | 400–499 | 客户端错误:请求有误或无法满足 |
| 5xx | 500–599 | 服务端错误:服务器处理请求时出错 |
4.2 1xx 信息类
| 状态码 | 含义 | 用途 | 特点 |
|---|---|---|---|
| 100 Continue | 请继续发送请求体 | 客户端在发送较大 body 前先发头并带 Expect: 100-continue,服务器同意则先回 100,客户端再发 body | 避免大 body 被拒绝后白传,节省带宽 |
| 101 Switching Protocols | 同意切换协议 | 升级到 WebSocket、HTTP/2 等时,服务器返回 101 并切换 | 连接从 HTTP 升级为其他协议,后续同连接用新协议 |
4.3 2xx 成功类
| 状态码 | 含义 | 用途 | 特点 |
|---|---|---|---|
| 200 OK | 请求成功 | 最通用:GET 取到资源、POST 处理成功、PUT/PATCH 更新成功等,且返回有 body | 有响应体;若无需返回内容可用 204 |
| 201 Created | 资源已创建 | POST 创建新资源(如新用户、新订单)后返回 | 通常带 Location 头指向新资源 URL;可选在 body 中返回资源表述 |
| 204 No Content | 成功但无返回内容 | 请求成功且服务器不返回 body,如 DELETE 成功、PUT 更新后无需回传 | 无响应体;客户端不应依赖 body 内容 |
| 206 Partial Content | 部分内容 | 支持范围请求时,返回请求范围内的那一段(如断点续传、分片下载) | 需配合 Range 请求头;响应头常带 Content-Range 说明区间与总长 |
4.4 3xx 重定向类
| 状态码 | 含义 | 用途 | 特点 |
|---|---|---|---|
| 301 Moved Permanently | 永久重定向 | 资源长期迁到新 URL(如域名更换、目录永久调整) | 用 Location 指明新 URL;浏览器/代理可缓存;搜索引擎会把权重转到新 URL |
| 302 Found | 临时重定向 | 资源临时从别处提供(如临时维护页、A/B 跳转、登录后跳回) | 用 Location 指明临时 URL;不要求更新书签或缓存;SEO 不转移权重 |
| 303 See Other | 见其他位置 | POST 提交后引导用 GET 访问新 URL(如创建成功跳转到详情页) | 明确要求用 GET 访问 Location;与 302 区别在于语义上「用 GET 取新资源」 |
| 304 Not Modified | 未修改,用缓存 | 协商缓存:客户端带 If-None-Match 或 If-Modified-Since,服务器判断资源未变则回 304 | 无响应体,客户端用本地缓存;节省带宽,常用于静态资源与接口缓存 |
301 与 302 考点小结
- 301:永久重定向;浏览器/搜索引擎可更新为长期使用新 URL。
- 302:临时重定向;不要求更新书签,SEO 不转移权重。
- 选型:换域名、目录永久迁移用 301;登录后跳回、A/B 跳转用 302。
补充:307(临时)、308(永久)与 302、301 类似,但规定重定向后不改变原请求方法(POST 仍用 POST);302/301 早期部分浏览器会把 POST 改成 GET,需严格保留方法时用 307/308。
4.5 4xx 客户端错误类
| 状态码 | 含义 | 用途 | 特点 |
|---|---|---|---|
| 400 Bad Request | 错误请求 | 请求语法、格式或参数有误(如 JSON 非法、必填项缺失、类型错误) | 客户端应修正请求再重试;可在 body 中返回具体错误信息 |
| 401 Unauthorized | 未认证 | 需要登录或 Token,但未提供或已失效 | 常带 WWW-Authenticate 说明认证方式;客户端应引导登录或刷新 Token |
| 403 Forbidden | 禁止访问 | 身份已识别,但无权限访问该资源(如权限不足、IP 被封、资源禁止访问) | 与 401 区别:401 是「未登录」,403 是「已登录但没权限」 |
| 404 Not Found | 未找到 | 请求的 URL 对应资源不存在或对当前用户不可见 | 最常见错误码之一;也可用于「存在但不想暴露」时统一返回 404 |
| 405 Method Not Allowed | 方法不允许 | 该 URL 不支持当前请求方法(如对只读接口发 POST) | 响应头 Allow 列出允许的方法(如 Allow: GET, HEAD) |
| 429 Too Many Requests | 请求过多 | 触发限流:同一客户端或同一 key 在时间窗口内请求次数超限 | 常带 Retry-After 建议多久后重试;客户端应降频或排队重试 |
4.6 5xx 服务端错误类
| 状态码 | 含义 | 用途 | 特点 |
|---|---|---|---|
| 500 Internal Server Error | 服务器内部错误 | 服务端处理请求时发生未捕获异常、配置错误或依赖失败 | 客户端无法通过改请求修复,可稍后重试;不应把业务校验错误当 500 |
| 502 Bad Gateway | 网关错误 | 作为代理/网关时,从上游(如应用服务器)收到无效或错误响应 | 常见于 Nginx 反向代理后端挂掉或返回非 HTTP;需检查上游服务与网络 |
| 503 Service Unavailable | 服务不可用 | 服务暂时过载、维护或不可用,请稍后再试 | 可带 Retry-After;与 502 区别:502 是「上游坏了」,503 是「本机过载或主动不可用」 |
| 504 Gateway Timeout | 网关超时 | 作为代理/网关时,等待上游响应超时 | 上游处理过慢或网络问题;客户端可稍后重试 |
502 / 503 / 504 考点小结
| 状态码 | 含义 |
|---|---|
| 502 | 网关从上游收到无效或错误响应(上游挂了、返回非 HTTP) |
| 503 | 本服务主动表示暂时不可用(过载、维护) |
| 504 | 网关等上游响应超时(上游太慢或网络问题) |
记:502 上游坏了/乱回,503 本机过载或维护,504 等上游响应超时。
五、HTTP 头部(常用)
头部用于传递请求/响应的元信息:内容类型、长度、缓存、认证等。键不区分大小写,建议按规范首字母大写。
5.1 请求头
| 请求头 | 含义 | 取值示例 | 用途与注意 |
|---|---|---|---|
| Host | 目标主机与端口 | Host: api.example.com、Host: example.com:8080 | HTTP/1.1 必须;虚拟主机靠此区分;缺省端口可省略 |
| User-Agent | 客户端标识 | User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0 | 服务端做兼容、统计、限流;可伪造,勿用于安全判断 |
| Accept | 希望接收的媒体类型 | Accept: application/json、Accept: text/html, application/xml;q=0.9 | 内容协商;q 表示优先级;服务端可选 406 表示无法满足 |
| Accept-Language | 希望接收的语言 | Accept-Language: zh-CN, zh;q=0.9, en;q=0.8 | 多语言站点或接口返回对应语言版本 |
| Accept-Encoding | 希望接收的编码(压缩) | Accept-Encoding: gzip, deflate, br | 服务端可对 body 压缩(如 gzip);响应头用 Content-Encoding 说明实际编码 |
| Content-Type | 请求体的媒体类型 | Content-Type: application/json、application/x-www-form-urlencoded、multipart/form-data; boundary=----xxx | 有 body 时建议显式设置;表单上传用 multipart |
| Content-Length | 请求体字节长度 | Content-Length: 1024 | 有 body 时应正确设置;分块传输时不用此头 |
| Cookie | 携带已存储的 Cookie | Cookie: sessionid=abc; theme=dark | 由浏览器或客户端按域名/路径自动携带;由服务端通过 Set-Cookie 响应头下发并写入 |
| Authorization | 认证信息 | Authorization: Bearer <token>、Authorization: Basic <base64(user:pass)> | 常见:Bearer(JWT)、Basic(base64 编码的 用户名:密码);401 时可用 WWW-Authenticate 指明方式 |
| Connection | 连接控制 | Connection: keep-alive、Connection: close | HTTP/1.1 默认 keep-alive;设为 close 表示本请求后关闭连接 |
| Referer | 当前请求的来源页 URL | Referer: https://www.example.com/page | 统计、防盗链、CSRF 校验;HTTPS→HTTP 时浏览器常不发送;可用 Referrer-Policy 控制 |
| Origin | 请求来源域(不含路径) | Origin: https://www.example.com | 跨域请求(如 CORS)时携带;服务端据此返回 Access-Control-Allow-Origin 等 |
| If-None-Match | 协商缓存:资源 ETag | If-None-Match: "abc123" | 与响应 ETag 对比;未变则 304,变则 200 + 新内容 |
| If-Modified-Since | 协商缓存:资源修改时间 | If-Modified-Since: Wed, 21 Oct 2024 10:00:00 GMT | 与响应 Last-Modified 对比;未变则 304 |
| Range | 范围请求 | Range: bytes=0-1023 | 只请求资源的一部分;服务端支持则回 206 Partial Content 与 Content-Range,用于断点续传、分片下载 |
5.2 响应头
| 响应头 | 含义 | 取值示例 | 用途与注意 |
|---|---|---|---|
| Content-Type | 响应体的媒体类型与编码 | Content-Type: text/html; charset=utf-8、Content-Type: application/json | 客户端据此解析 body;可带 charset |
| Content-Length | 响应体字节长度 | Content-Length: 2048 | 非分块响应时常用;客户端可据此做进度或校验 |
| Content-Encoding | 响应体使用的编码(压缩) | Content-Encoding: gzip | 表示 body 已压缩,客户端需先解压再按 Content-Type 解析 |
| Cache-Control | 缓存策略 | Cache-Control: public, max-age=3600、no-cache、no-store | 控制是否缓存、缓存时长、是否必须再验证;优先于 Expires |
| Expires | 缓存过期时间(绝对时间) | Expires: Thu, 01 Dec 2024 12:00:00 GMT | 旧式缓存;与 Cache-Control 同时存在时以 Cache-Control 为准 |
| Last-Modified | 资源最后修改时间 | Last-Modified: Wed, 21 Oct 2024 10:00:00 GMT | 协商缓存;客户端下次带 If-Modified-Since 比较,未变可 304 |
| ETag | 资源版本标识 | ETag: "abc123"、ETag: W/"weak123" | 协商缓存;客户端下次带 If-None-Match 比较;比 Last-Modified 更细 |
| Set-Cookie | 下发 Cookie | Set-Cookie: sid=xxx; Path=/; HttpOnly; Secure; SameSite=Strict | 可多次出现;常用属性:Path、Domain、Max-Age/Expires、HttpOnly(禁止 JS 读)、Secure(仅 HTTPS)、SameSite(防 CSRF) |
| Location | 重定向或新资源 URL | Location: https://example.com/new、Location: /api/users/123 | 3xx 重定向时必填;201 时指向新创建资源(可相对或绝对) |
| Server | 服务器软件信息 | Server: nginx/1.18.0 | 生产环境常隐藏或写通用名,避免暴露版本 |
| Date | 响应生成时间 | Date: Wed, 21 Oct 2024 10:00:00 GMT | 建议 GMT;用于缓存计算、日志与调试 |
| Access-Control-Allow-Origin | 允许的跨域来源 | Access-Control-Allow-Origin: https://www.example.com 或 * | CORS:允许哪些源可读本响应;预检还会用到 Access-Control-Allow-Methods、Access-Control-Allow-Headers 等 |
| Vary | 内容协商与缓存 | Vary: Accept-Encoding, User-Agent | 告诉缓存:仅当这些请求头的值与缓存时一致时才可用该缓存;否则需重新向服务器请求 |
5.3 CORS 与预检请求(常考)
同源与跨域
- 同源 = 协议、域名、端口三者一致;跨域 = 任一项不同。
- 浏览器同源策略下,前端脚本请求跨域地址时,默认会限制读取响应(如 XHR/fetch 报错)。
- CORS(跨域资源共享):服务端返回
Access-Control-Allow-Origin等头,告诉浏览器「允许该来源读取本响应」。
| 类型 | 条件(满足即为简单请求) | 是否发预检 |
|---|---|---|
| 简单请求 | 方法为 GET / HEAD / POST 之一;头仅含 Accept、Accept-Language、Content-Language、Content-Type(且 Content-Type 仅为 application/x-www-form-urlencoded、multipart/form-data、text/plain)等简单头 | 不发 OPTIONS,直接发本次请求;服务器回 Access-Control-Allow-Origin 等即可 |
| 预检请求 | 用了 PUT/DELETE/PATCH、或带了自定义头(如 Authorization、X-Requested-With)、或 Content-Type 为 application/json 等 | 浏览器会先发 OPTIONS 请求(预检),询问服务器是否允许该方法、该头;服务器回 204 且带 Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Allow-Origin 等;通过后再发真正的 GET/POST/… |
考点小结
- 跨域时浏览器先判断是否为简单请求;非简单请求会先发 OPTIONS 预检,通过后再发实际请求。
- 服务端需对 OPTIONS 返回允许的方法与头,并带
Access-Control-Allow-Origin;若带 Cookie 则需Access-Control-Allow-Credentials: true且不能为*。
CORS 预检流程示意:
flowchart LR
A[跨域请求] --> B{简单请求?}
B -->|是| C[直接发 GET/POST 等]
B -->|否| D[先发 OPTIONS 预检]
D --> E{Allow-Origin 等?}
E -->|通过| F[再发实际请求]
E -->|不通过| G[跨域失败]
C --> H[回 Access-Control-Allow-Origin]
六、HTTP 缓存
HTTP 缓存:浏览器(或代理)把某次请求得到的响应存起来,下次要同一资源时直接用这份副本,减少请求、省带宽、加快加载。
下次要同一资源时,浏览器怎么决定? 两种决策方式(不是两种「存法」):
- 强缓存:在有效期内不发请求,直接用本地副本。
- 协商缓存:过期后(或要求每次验证时)发请求,带「上次的版本信息」;服务器判断是否变化 → 未变回 304 用本地,已变回 200 和新内容。
小结:强缓存 = 有效期内直接用;协商缓存 = 先问服务器,再根据 304/200 决定用本地还是新内容。
缓存决策流程示意:
flowchart LR
A[请求资源] --> B{有本地缓存?}
B -->|否| C[请求服务器 200 存缓存]
B -->|是| D{强缓存有效?}
D -->|是| E[不发请求 用本地 cache]
D -->|否| F[带 If-None-Match 等请求]
F --> G{资源变化?}
G -->|未变| H[304 用本地缓存]
G -->|已变| I[200 更新缓存]
6.1 强缓存与协商缓存对照
| 类型 | 是否发请求 | 谁决定「用不用本地副本」 | 典型状态码 | 由哪些响应头控制 |
|---|---|---|---|---|
| 强缓存 | 不发请求 | 浏览器自己(看本地是否在有效期内) | 无(不产生 HTTP 请求) | Cache-Control: max-age=…、Expires |
| 协商缓存 | 发请求,带条件头 | 服务器(根据条件头判断是否未修改) | 304(用本地)或 200(新内容) | Last-Modified、ETag(请求时对应 If-Modified-Since、If-None-Match) |
- 强缓存:响应里带了
max-age或未过期的Expires时,在有效期内浏览器不会向服务器发请求,直接用本地副本;过期后才会发请求,此时可能走协商缓存(304/200)或直接拿到新的 200。 - 协商缓存:缓存过期或响应要求「每次都要验证」(如
no-cache)时,浏览器会发请求,并带上上次保存的 If-Modified-Since 或 If-None-Match;服务器比较后若资源未变则返回 304(不返 body),浏览器用本地缓存;若已变则返回 200 和新内容。
6.2 缓存流程简述
- 首次请求(无本地缓存):请求服务器 → 200 + 响应头(Cache-Control、ETag/Last-Modified 等)→ 浏览器存下响应与这些头。
- 再次请求(未过期):若强缓存有效(如
max-age未到期)→ 不发请求,直接用本地。 - 再次请求(已过期或 no-cache):发请求并带 If-None-Match(优先)或 If-Modified-Since → 服务器比较:
- 未修改 → 返回 304(无 body),浏览器用本地缓存;
- 已修改 → 返回 200 + 新 body,浏览器更新本地缓存。
304 之后会一直协商吗?
不一定。304 响应里可以带新的响应头(如 Cache-Control: max-age=3600、Expires 等),浏览器会更新到该资源的缓存元数据。
- 304 里带了新的
max-age或未过期的Expires:新有效期内再次访问 → 走强缓存(不发请求);新有效期过了再走协商缓存。 - 304 里没给新有效期(或给了
no-cache):下次访问 → 再次发条件请求,继续走协商缓存。
结论:是否「每次都要协商」取决于 304 里是否设置了新的过期时间。
6.3 Cache-Control 常用指令
响应头中的 Cache-Control(可组合,多个指令用逗号分隔):
| 指令 | 含义 | 说明 |
|---|---|---|
| no-store | 不缓存 | 不存到磁盘/内存,每次都要从服务器取;最严格,敏感数据用 |
| no-cache | 可存但每次都要验证 | 会缓存,但再用前必须带条件头向服务器验证;未变则 304,变则 200 |
| max-age=秒 | 强缓存时长 | 在此秒数内不发请求,直接用本地;如 max-age=3600 表示 1 小时内强缓存 |
| s-maxage=秒 | 共享缓存(如 CDN)的最大年龄 | 仅对 public 的共享缓存生效,覆盖 max-age |
| private | 仅浏览器可缓存 | 中间代理(CDN、反向代理)不应缓存,只允许最终用户浏览器缓存 |
| public | 允许中间节点缓存 | 浏览器和代理/CDN 都可以缓存 |
| must-revalidate | 过期后必须再验证 | 过期后不能直接用旧缓存,必须向服务器验证(可 304) |
请求头中的 Cache-Control:如 no-cache 表示「我希望拿到最新内容」,可强制走协商(仍可能 304)。
6.4 Last-Modified 与 ETag
两者都用于协商缓存:服务器在响应里给出「资源版本」,下次请求时客户端带上对应条件头,服务器据此返回 304 或 200。
| 机制 | 响应头 | 请求条件头 | 特点 |
|---|---|---|---|
| Last-Modified | Last-Modified: <GMT 时间> | If-Modified-Since: <同上> | 精度到秒;1 秒内多次修改难区分;某些场景下可能被故意不改时间只改内容 |
| ETag | ETag: "abc123" 或 W/"weak" | If-None-Match: "abc123" | 资源版本标识(如哈希),更精确;若同时存在,优先用 ETag(If-None-Match),因更可靠 |
- ETag 强弱:强 ETag(
"xxx")要求字节完全一致;弱 ETag(W/"xxx")表示语义等价即可。 - 优先级:若响应同时有 Last-Modified 和 ETag,规范建议以 ETag 为准(请求带 If-None-Match),避免时间精度与时钟问题。
6.5 小结
- 缓存命中顺序(常考)
- 先看强缓存是否有效(
max-age未过期、Expires未到)→ 有效则不发请求直接用本地(memory cache / disk cache,通常先内存后磁盘)。 - 无效或 no-cache 时再发请求走协商缓存(带 If-None-Match / If-Modified-Since)→ 服务器回 304 用本地或 200 更新。
- 先看强缓存是否有效(
- 强缓存:看 Cache-Control(max-age)、Expires;有效期内不发请求。
- 协商缓存:看 ETag / Last-Modified,请求带 If-None-Match / If-Modified-Since;服务器决定 304 或 200。
- 304 之后:304 里若带新的 Cache-Control / Expires,浏览器会更新本地过期时间,新有效期内再走强缓存;若没带,下次仍发条件请求走协商缓存。
- 优先级:Cache-Control 优先于 Expires;ETag 优先于 Last-Modified(两者同时存在时)。
七、连接管理
- 背景:HTTP 基于 TCP,每次发请求前都要先建立 TCP 连接。
- 连接管理要解决的问题:是「一个请求用一条连接、用完就关」,还是「一条连接复用、连续发多个请求」?
- 短连接:一个请求用一条连接,用完就关。
- 长连接(Keep-Alive):一条连接复用,连续发多个请求、收多个响应。
- 管道化:在长连接上「连续发多个请求、不等响应就发下一个」;属 HTTP/1.1,与长连接并存(先有长连接才能管道化)。HTTP/1.x 下易队头阻塞,实际少用;HTTP/2 用多路复用从协议层解决。
连接方式对比示意:
flowchart LR
A1[建连] --> A2[请求1 响应1]
A2 --> A3[关连]
A3 --> A4[再建连]
A4 --> A5[请求2 响应2]
B1[建连] --> B2[请求1]
B2 --> B3[响应1]
B3 --> B4[请求2]
B4 --> B5[响应2]
C1[建连] --> C2[请求1+2+3]
C2 --> C3[响应1+2+3 按序]
7.1 短连接
| 项目 | 说明 |
|---|---|
| 做法 | 每次 HTTP 请求都新建一条 TCP 连接,请求完成后立即关闭该连接;下次请求再重新建连。 |
| 典型版本 | HTTP/1.0 默认如此(当时未标准化 Keep-Alive)。 |
| 优点 | 实现简单;服务器无需维护连接状态,适合无状态、请求量不大的场景。 |
| 缺点 | 每次请求都要经历 TCP 三次握手、四次挥手,延迟与开销大;高并发时建连数多,占用端口与资源。 |
7.2 长连接(Keep-Alive)
| 项目 | 说明 |
|---|---|
| 做法 | 复用同一条 TCP 连接,在其上连续发送多个 HTTP 请求、接收多个响应;连接在一段时间内保持打开,由客户端或服务器在合适时机关闭(或由超时、最大请求数等策略关闭)。 |
| 典型版本 | HTTP/1.1 默认使用长连接(即默认 Connection: keep-alive);若不想复用,需显式发 Connection: close。 |
| 如何声明 | 请求头 Connection: keep-alive(HTTP/1.1 下可省略,因默认即 keep-alive);服务器若支持,可响应头里带 Keep-Alive: timeout=60, max=100 等,表示空闲多少秒或最多多少个请求后关闭。 |
| 优点 | 减少 TCP 建连/断连次数,降低延迟、节省资源;同一域名下多个请求共用一个连接,更高效。 |
| 注意 | 服务器需在一定时间内或请求数上限内关闭空闲连接,避免占满资源;客户端也可能主动发 Connection: close 要求关闭。 |
7.3 管道化(Pipelining)
| 项目 | 说明 |
|---|---|
| 典型版本与长连接关系 | HTTP/1.1 中定义;与长连接并存——管道化依赖长连接:只有先建立并保持一条长连接,才能在该连接上「连续发多个请求不等响应」。二者不是二选一,而是「长连接是基础,管道化是在长连接上的可选优化」。 |
| 做法 | 在同一条长连接上,客户端不等待上一个响应返回就连续发出多个请求;服务器按收到顺序依次处理并按序回响应。 |
| 与普通长连接区别 | 普通长连接是「发一个请求 → 等响应 → 再发下一个」;管道化是「连续发多个请求,再按序收多个响应」。 |
| 为何很少用 | 容易遇到队头阻塞(Head-of-Line Blocking):若第一个请求的响应很慢或卡住,后面的响应都会被堵住,即使它们本身已经处理完;且中间代理、服务器实现不一,兼容性差。 |
| 现状 | 浏览器中实际很少启用;HTTP/2 通过多路复用在一条连接上并行多个请求/响应流,从协议层避免了「一个慢请求堵住整条连接」的问题。 |
7.4 小结
- 短连接:一请求一连接,用完即关;HTTP/1.0 默认;简单但延迟和建连开销大。
- 长连接:一连接多请求;HTTP/1.1 默认 Keep-Alive;靠 Connection / Keep-Alive 控制。
- 管道化:HTTP/1.1,依赖长连接、与长连接并存;在长连接上连续发请求不等响应;HTTP/1.x 下队头阻塞明显,实际少用;HTTP/2 多路复用替代该思路并解决队头阻塞。
八、Cookie 与 Session
HTTP 本身是无状态的:服务器不记录「上一次是谁、做了什么」。要在多次请求之间维持登录态、偏好等,需要「会话」机制。常见两种:
- Cookie:数据存客户端,每次请求自动带上。
- Session:数据存服务端,客户端只持有一个标识(通常用 Cookie 传 SessionID)。
Cookie 与 Session 流程示意:
flowchart LR
A1[首次访问] --> A2[Set-Cookie]
A2 --> A3[浏览器存 Cookie]
A3 --> A4[后续带 Cookie]
A4 --> A5[服务器识别用户]
B1[登录/首次] --> B2[建 Session]
B2 --> B3[Set-Cookie SessionID]
B3 --> B4[后续带 SessionID]
B4 --> B5[服务器查 Session]
8.1 Cookie
| 项目 | 说明 |
|---|---|
| 是什么 | 由服务器通过响应头 Set-Cookie 下发给浏览器的一小块数据;浏览器会按域名、路径等规则自动保存,并在后续同域(同路径)请求里通过请求头 Cookie 自动携带。 |
| 流程 | 首次:服务器响应里带 Set-Cookie: name=value; ... → 浏览器存下;之后:同一域名的请求自动带 Cookie: name=value; ...,服务器据此识别用户或读取状态。 |
| 常用属性 | Domain(生效域名)、Path(生效路径)、Expires / Max-Age(过期时间)、Secure(仅 HTTPS 发送)、HttpOnly(禁止 JS 读取,防 XSS 窃取)、SameSite(限制跨站携带,防 CSRF,如 Strict / Lax / None)。 |
| 限制 | 单条 Cookie 约 4KB;每域名下条数有限(如几十到几百,因浏览器而异);总大小也有限制;存敏感信息需配合 Secure + HttpOnly。 |
| 典型用途 | 登录态(SessionID)、偏好设置、追踪标识等;敏感数据不宜明文放 Cookie,可只放 ID,真实数据放服务端(即 Session)。 |
8.2 Session
| 项目 | 说明 |
|---|---|
| 是什么 | 服务器为一次「会话」维护的一份服务端状态(如用户信息、购物车);客户端不存这份数据,只持有一个会话标识(SessionID);每次请求把 SessionID 发给服务器,服务器据此查出对应用户的会话数据。 |
| SessionID 怎么传 | 常见做法是用 Cookie 传:服务器在登录或首次访问时响应里带 Set-Cookie: JSESSIONID=xxx(或类似名),后续请求浏览器自动带该 Cookie,服务器用 xxx 查 Session。也可用 URL 参数或自定义头传递,但 Cookie 最常用。 |
| 客户端拿 SessionID 干什么用 | 客户端不拿 SessionID 做任何业务逻辑,只是在每次请求里把它原样带给服务器。服务器收到后根据这个 ID 查到对应的 Session(用户信息、登录态等),从而知道「这次请求是谁、处于什么会话」。对客户端来说,SessionID 就是「下次请求时带给服务器的一张票」,真正使用它的是服务器。 |
| 生命周期 | 服务器创建 Session 时生成 SessionID 并写入 Cookie;在过期时间内或用户关闭浏览器(若为会话级 Cookie)前有效;服务端可主动使 Session 失效(如登出时删除对应 Session)。 |
| 优点 | 敏感数据、大量数据存服务端,客户端只传 ID,相对安全;不受 Cookie 单条 4KB、条数等限制。 |
| 注意 | 占用服务端内存或存储;多机/分布式时需共享 Session(如存 Redis、数据库),否则换机器就找不到该 Session。 |
8.3 Cookie 与 Session 的关系与区别
| 对比项 | Cookie | Session |
|---|---|---|
| 数据存哪 | 客户端(浏览器) | 服务端 |
| 客户端持有什么 | Cookie 的键值(可能有多条) | 通常仅一个 SessionID(常放在 Cookie 里) |
| 大小与数量 | 单条约 4KB,每域条数有限 | 服务端可存较多数据,不受 Cookie 限制 |
| 安全性 | 在客户端,可被窃取、篡改;需 HttpOnly、Secure、SameSite 等加固 | 数据在服务端,相对安全;SessionID 泄露仍可能被冒用,故也需 Secure/HttpOnly |
| 典型用法 | 存偏好、追踪 ID,或仅存 SessionID | 存登录态、用户信息、购物车等敏感或大量数据 |
关系:Session 机制通常依赖 Cookie 传递 SessionID——Cookie 里只放一个 ID,真实会话数据在服务端用 Session 存。
8.4 小结
- Cookie:服务端用 Set-Cookie 下发,浏览器自动存、自动带;可设 Domain、Path、Expires、Secure、HttpOnly、SameSite;有大小与条数限制;可单独用,也可只存 SessionID 配合 Session。
- Session:数据在服务端,客户端只持 SessionID(常通过 Cookie 传);适合敏感或大量会话数据;分布式需共享存储。
- 二者:不是二选一,常一起用——Cookie 传 SessionID,Session 存真实会话数据。
九、HTTPS 基础
HTTPS 在 HTTP 之下增加 SSL/TLS 层,对传输内容加密并对服务器做身份校验,可理解为「HTTP over TLS」。下面先对比 HTTP 与 HTTPS,再说明 TLS 协议、握手、加密方式等基础。
9.1 HTTP 与 HTTPS 对比
| 项目 | HTTP | HTTPS |
|---|---|---|
| 全称 | HyperText Transfer Protocol | 常称 HTTP Secure,即 HTTP + SSL/TLS |
| 默认端口 | 80 | 443 |
| URL 写法 | http://example.com | https://example.com |
| 传输内容 | 明文(请求/响应、头部、body 均可见) | 加密(除 TLS 握手等外,应用层数据加密传输) |
| 身份校验 | 无;不验证对方身份 | 通过数字证书验证服务器身份,防止冒充 |
| 完整性 | 无;内容可被篡改而不易被发现 | 有(如 MAC、签名等),可发现篡改 |
| 性能 | 无加解密与握手开销 | 有 TLS 握手与加解密开销;可通过会话复用、HTTP/2 等优化,通常可接受 |
| 浏览器表现 | 无特殊提示 | 地址栏锁标、证书有效时无警告;证书无效或过期会提示不安全 |
| 典型场景 | 内网、测试、不涉密展示页 | 生产环境、登录/支付、含敏感信息的页面;现代站点普遍要求 HTTPS |
为何要用 HTTPS
- 防窃听(明文可被截获)、防篡改(完整性校验)、防中间人(证书校验服务器身份)。
- 合规与用户信任:敏感操作、登录、支付等通常要求 HTTPS。
- 生产与敏感场景应使用 HTTPS;仅内网或临时测试可酌情用 HTTP。
9.2 SSL/TLS 协议
| 项目 | 说明 |
|---|---|
| SSL 与 TLS 是分开还是同时用 | 分开使用,不是同时用。SSL 和 TLS 是两套不同协议(SSL 在先,TLS 是其后继);一次连接只会协商使用其中一种(如 TLS 1.2 或 TLS 1.3)。现在实际只用 TLS;说「SSL/TLS」多是习惯叫法,实际指的就是 TLS。 |
| SSL | Secure Sockets Layer,旧协议,已废弃;如 SSL 3.0 存在 POODLE 等漏洞,不应再使用。 |
| TLS | Transport Layer Security,现行标准,替代 SSL;日常说「SSL/TLS」时一般指 TLS。 |
| 版本建议 | 仅启用 TLS 1.2、TLS 1.3;禁用 TLS 1.0/1.1 和所有 SSL。TLS 1.3 更简洁、更快、去掉不安全算法。 |
9.3 握手与性能
| 项目 | 说明 |
|---|---|
| 握手目的 | 协商 TLS 版本与加密套件、验证服务器证书、交换密钥(或协商出会话密钥),从而建立加密通道。 |
| 过程简述 | 客户端发 ClientHello(版本、支持的套件等)→ 服务端回 ServerHello、证书、ServerHelloDone → 客户端校验证书、发密钥交换与 Finished → 服务端回 Finished,之后应用数据在加密通道中传输。 |
| RTT | TLS 1.2 完整握手约 2-RTT(两次往返);TLS 1.3 可 1-RTT,且支持 0-RTT 恢复(有安全权衡)。 |
| 性能 | 握手与加解密有 CPU 开销;可通过 会话复用(Session Resumption)、HTTP/2 单连接多路复用、CDN、硬件加速等优化;现代环境下性能通常可接受。 |
9.4 加密方式概览
| 类型 | 作用 | 常见算法 | 说明 |
|---|---|---|---|
| 对称加密 | 加密应用层数据(bulk 数据) | AES、ChaCha20 等 | 编解码快;密钥需安全协商,通常由握手阶段用非对称或 DH 等方式得到。 |
| 非对称加密 | 密钥交换、身份验证(证书签名等) | RSA、ECDHE、ECDSA 等 | 公钥加密、私钥解密(或反之签名/验签);计算量大,一般只用于握手与密钥交换。 |
| 混合加密 | 实际用法 | 握手用非对称/密钥交换,数据用对称 | 兼顾安全与性能:用非对称建立共享密钥,用对称加密业务数据。 |
| 哈希/完整性 | 签名、完整性校验 | SHA-256、SHA-384 等 | 证书签名、Finished 校验等;避免 MD5、SHA-1(已不推荐)。 |
9.5 HTTPS 请求完整流程(考点)
一次完整的 HTTPS 请求从「输入 URL」到「拿到响应」,大致经历以下步骤(面试/笔试常考)。
整体流程示意:
flowchart LR
A[DNS 解析] --> B[TCP 握手 443]
B --> C[TLS 握手]
C --> D[发 HTTP 请求]
D --> E[返回响应]
E --> F[关闭或复用]
TLS 握手(步骤 3)流程示意:
flowchart LR
T1[ClientHello] --> T2[ServerHello+证书]
T2 --> T3[客户端校验证书]
T3 --> T4[密钥交换]
T4 --> T5[Finished]
T5 --> T6[加密 HTTP 请求/响应]
| 步骤 | 阶段 | 说明 |
|---|---|---|
| 1 | DNS 解析 | 浏览器根据域名(如 https://www.example.com)解析出服务器 IP 地址;可能走本地缓存、hosts、或 DNS 服务器。 |
| 2 | TCP 三次握手 | 客户端与服务器在 443 端口建立 TCP 连接(SYN → SYN+ACK → ACK),为后续 TLS 和 HTTP 提供可靠传输。 |
| 3 | TLS 握手 | 在已建立的 TCP 连接上进行 TLS 握手(见下),协商版本与加密套件、校验证书、交换密钥,建立加密通道。握手中通过 SNI(Server Name Indication)把要访问的域名发给服务端,便于同一 IP 多域名时选对证书。 |
| 4 | 发送 HTTP 请求 | 在 TLS 加密通道上,按 HTTP 协议发送请求(方法、URL、请求头、请求体等),内容已被加密。 |
| 5 | 服务器处理并返回响应 | 服务器解密请求、处理业务后,在加密通道上返回 HTTP 响应(状态码、响应头、响应体),内容同样加密传输。 |
| 6 | 关闭连接 | 双方可发送 TLS 关闭通知,然后 TCP 四次挥手释放连接;若为 Keep-Alive,连接可复用,下次同域请求可能跳过步骤 2、3。 |
TLS 握手(步骤 3)细化(常单独考)
TLS 握手在 TCP 连接建立后进行,目的是协商加密参数、校验证书、交换密钥,从而建立加密通道。五步概括如下。
| 步骤 | 名称 | 谁发/谁做 | 内容与作用 | 考点提示 |
|---|---|---|---|---|
| 1 | ClientHello | 客户端 | 发送支持的 TLS 版本、加密套件列表、随机数等;服务端据此选择版本与套件。 | 先发版本与套件,此时尚未带证书 |
| 2 | ServerHello + 证书 | 服务端 | 回 ServerHello:选定版本与加密套件、返回随机数;随后下发服务器证书(含公钥),供客户端校验证书并获取公钥。 | 证书里带公钥,私钥只在服务端 |
| 3 | 客户端校验证书 | 客户端 | 验证证书链、有效期、域名(如 SNI)等;通过后从证书中取出服务器公钥,用于后续密钥交换。 | 链、有效期、域名、吊销(可选) |
| 4 | 密钥交换 | 客户端 → 服务端 | 客户端生成预主密钥,用服务器公钥加密后发给服务端(或走 ECDHE 等协商);只有持有服务器私钥的服务端能解密得到预主密钥;双方再用预主密钥(及 Hello 中的随机数)推导出相同的会话密钥,后续应用数据用会话密钥加密。 | 预主密钥→会话密钥;常用 ECDHE |
| 5 | Finished | 双方 | 交换 Finished 消息,确认握手过程未被篡改;此后应用层数据均用会话密钥加密传输。 | 握手结束,进入加密应用数据阶段 |
服务器密钥还有用吗?
有用,且必不可少。
- 预主密钥是客户端生成的,但必须安全地让服务端也拿到,双方才能算出同一会话密钥。
- 客户端用证书里的服务器公钥加密预主密钥再发送;只有拥有服务器私钥的服务端能解密,中间人拿不到。
- 在密钥交换这一步,服务器公钥/私钥的作用就是:保护预主密钥只被客户端和服务端共享。
- 握手完成后,业务数据用会话密钥加密,服务器密钥不再参与每包数据的加解密,但在握手阶段是必需的。
小结:ClientHello → ServerHello+证书 → 客户端校验证书并取公钥 → 密钥交换得会话密钥 → Finished;之后 HTTP 在加密通道上传输。
HTTPS 请求流程小结:DNS 解析 → TCP 建连(443)→ TLS 握手(证书校验 + 密钥交换)→ 加密的 HTTP 请求/响应;关闭时 TLS 结束再 TCP 挥手(或保持长连接复用)。
十、HTTPS 证书与安全实践
10.1 证书的作用与结构
为什么需要证书
HTTPS 握手需要服务器的公钥,但对方可能是攻击者冒充的。证书用来解决「对方是不是这个网站」:
- CA 把「域名」和「公钥」绑在一起并签名。
- 手机/浏览器确认签名有效、域名对、没过期后,才用证书里的公钥继续握手,密钥就不会交给冒充的中间人。
| 项目 | 说明 |
|---|---|
| 作用 | 通俗说:证书 = 「谁(域名/身份)」+ 「公钥」+ 「CA 的签名」。客户端用证书做两件事:一、确认「眼前这台服务器确实拥有这个域名对应的私钥」(因为只有私钥能配合证书里的公钥完成握手);二、从证书里拿到公钥,用来后续加密通信。服务器的私钥只保存在服务器自己那里,绝不会通过证书发给你。 |
| 常见格式 | X.509 是证书的通用格式。CA 用自己私钥对证书内容做一次「签名」;你的设备里已经预装了一批可信 CA 的公钥,用这些公钥可以验签:能验过就说明这张证书确实被该 CA 签发过、没被改过。 |
X.509 证书主要字段:
| 字段 | 含义 |
|---|---|
| 版本、序列号 | 证书版本与唯一标识;序列号在吊销列表中用于指代某张证书。 |
| 签名算法 | CA 签发该证书时使用的算法(如 RSA-SHA256、ECDSA)。 |
| 颁发者(Issuer) | 签发该证书的 CA 名称;在链中用于找到「上一级」证书。 |
| 有效期(NotBefore / NotAfter) | 证书生效与过期时间;当前时间必须落在此区间内,否则视为无效。 |
| 主体(Subject) | 证书持有者(域名或组织);CN(Common Name)为早期主域名,现多依赖 SAN(Subject Alternative Name)列多个域名,以支持多域、泛域。 |
| 公钥 | 服务器公钥,用于 TLS 密钥交换与后续加密;客户端从证书中提取此公钥。 |
| 扩展 | 如 SAN(多域名)、密钥用途(Key Usage)、基本约束(Basic Constraints)等。 |
| CA 数字签名 | 对上述内容做哈希后用 CA 私钥签名;客户端用 CA 公钥验签,确保证书未被篡改且确由该 CA 签发。 |
10.2 证书链与 CA
证书链是什么
- 服务器下发的是一串证书:服务器证书 → 中间证书(可能多级)→ 根证书。
- 验证:从服务器证书开始,用「上一级公钥」验「下一级签名」,逐级到根证书;根证书必须在本地信任库中,否则整条链不认。
- 通俗说:每一级都有人「盖章」,最后盖章的必须是系统自带的可信 CA。
证书链验证流程示意:
flowchart LR
A[服务器证书] -->|中间证书公钥验签| B[中间证书]
B -->|根证书公钥验签| C[根证书]
C --> D{根在信任库?}
D -->|是| E[链可信]
D -->|否| F[链不信任]
| 项目 | 说明 |
|---|---|
| 链的验证过程 | ① 用中间证书里的公钥,验证服务器证书的签名是否有效。 ② 用根证书里的公钥,验证中间证书的签名是否有效。 ③ 再看根证书是不是在本机「信任库」里、有没有过期。任一步失败就断开连接、报错。 |
| 为何要链 | 根 CA 的私钥要严格保护、一般不直接给成千上万个网站签证书;所以根只给「中间 CA」签证书,再由中间 CA 给具体网站签。这样既安全,也方便以后换证书、换 CA。 |
| CA | 证书颁发机构:专门负责给网站签发证书、并在需要时吊销证书的机构。公共 CA(如 Let's Encrypt、DigiCert)已被系统/浏览器内置信任;私有 CA(公司自己建的)需要你在设备上先安装它的根证书,才会被信任。 |
| 申请证书 | 向 CA 提交 CSR(包含你的公钥和域名等信息),并完成域名验证(证明你确实控制这个域名),例如:在指定网址放一段指定内容(HTTP-01),或在 DNS 里加一条指定记录(DNS-01)。通过后 CA 才会给你签发证书。 |
10.3 证书验证、过期与吊销
客户端验证证书时,大致按下面顺序检查(有一项不通过就会连接失败或弹出「不安全」提示):
- 证书链:从服务器证书一路验到根证书,每一级签名都要对,且根证书必须在本地信任库里。
- 有效期:当前时间必须在证书的「生效时间」和「过期时间」之间。
- 域名:你访问的地址(如
api.example.com)必须出现在证书的域名列表(CN/SAN)里。 - 吊销(可选):这张证书没有被 CA 提前列入「作废名单」。
| 项目 | 说明 |
|---|---|
| 过期 | 过了证书上的过期时间就失效,浏览器会提示「证书已过期」。所以要在过期前续期并换上新证书;运维要盯紧到期时间(常见 90 天或 1 年),避免到期后全站报错。 |
| 吊销 | 有时证书还没过期,但因为私钥泄露、域名不用了等原因,需要提前作废;作废后客户端就不应再信任这张证书。 |
怎么查「有没有被吊销」?常见两种方式对比:
| 机制 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| CRL(证书吊销列表) | 客户端从 CA 下载一份「已吊销证书名单」,看当前证书的序列号在不在名单里 | 实现简单,可以缓存着用 | 名单可能很大,更新有延迟;每次拉取有流量开销 |
| OCSP(在线证书状态协议) | 客户端在握手时向 CA 的 OCSP 服务发一次请求:「这张证书有没有被吊销?」 | 结果较新,只查这一张证书 | 依赖网络,有延迟和隐私顾虑;OCSP 挂了可能影响建连 |
| OCSP Stapling | 服务器在握手时主动带上一份「自己证书没被吊销」的 OCSP 证明(服务器事先向 CA 要好的),客户端不用自己去问 CA | 客户端不用连 CA,更快、更省、更保护隐私 | 需要服务器侧配置,并定期向 CA 拉取这份证明 |
10.4 中间人攻击与防护
什么是中间人攻击(MITM)
- 你在 A,服务器在 B,中间有攻击者 C;数据经 C 才到 B,C 可偷看、篡改、伪造。
- 例如公共 Wi‑Fi 下,攻击者成为「中间节点」:请求先到他再转服务器,他就能看到或改动请求和响应。
HTTP 下会怎样
HTTP 是明文传输,中间人可以直接看到你在访问什么、提交什么内容(如密码、表单),也可以篡改页面或响应。没有任何加密和身份校验,风险很大。
HTTPS 下为什么能防住(前提是正确校验证书)
HTTPS 会做两件事:加密和身份校验。
- 加密:握手成功后,数据用协商出的密钥加密,中间人看不到明文。
- 身份校验:服务器会出示证书,证明「我是这个域名对应的服务器」。证书是由可信 CA 签发的,且只有拥有该域名私钥的服务器才能完成 TLS 握手。中间人没有真服务器的私钥,所以无法冒充真服务器;客户端校验证书(链、有效期、域名、吊销)通过后,才会用证书里的公钥继续握手,这样密钥就不会交给中间人。
什么情况下 HTTPS 仍会被中间人攻破
如果客户端不校验证书、或校验证书失败后仍选择继续连接,就会出问题。例如:
- 开发时为了抓包,在代码里「信任所有证书」或关掉证书校验,且这段逻辑被带到生产环境;
- 用户访问时遇到证书错误(自签名、域名不匹配、过期等),被诱导点击「继续访问」「高级 → 继续前往」;
- 设备上被安装了恶意根证书(如某些抓包工具、恶意软件),攻击者用这张根证书签一张「假」的服务器证书,客户端会认为它可信。
这些情况下,中间人可以让你和他建立一条「假」的 HTTPS 连接(他和你加密通信,他再和真服务器加密通信),他就能解密、查看、篡改你的数据。
防护要点总结
| 项目 | 说明 |
|---|---|
| 必须用 HTTPS,并严格校验证书 | 不要在生产环境关闭证书校验、不要「信任所有证书」或「信任所有主机名」;在公共 Wi‑Fi 等不可信网络下尤其不要关校验。服务端要配置完整证书链(把中间证书也发给客户端),否则客户端可能验不过。 |
| HSTS(HTTP Strict Transport Security) | 服务器通过响应头告诉浏览器:「这个站以后只许用 HTTPS 访问」。浏览器在有效期内会强制用 HTTPS,即使用户输入了 http:// 也会自动跳成 https://,减少第一次访问被劫持或输错协议的风险。 |
| 其他 | 页面用 HTTPS 时,里面的图片、脚本等资源也要用 HTTPS,不要出现「混合内容」(HTTPS 页里请求 HTTP 资源,可能被篡改)。要提醒用户不要随意点击「忽略证书警告」。高安全场景可再加证书锁定(见下)。 |
HTTPS 抓包原理(常考)
- 抓包工具在本机/手机安装自己的根证书并被信任后,可解密 HTTPS。
- 过程:浏览器 → 抓包工具(用该根证书签发「假」服务器证书)→ 真实服务器;浏览器信任该根证书,认为「假」证书合法,与抓包工具建 TLS;抓包工具再与真服务器建 TLS,从而解密、查看、篡改。
- 结论:HTTPS 防的是「未信任的」中间人;用户一旦信任某 CA(如抓包根证书),该 CA 就能做中间人。生产环境不要信任此类证书;抓包仅限开发环境。
10.5 证书锁定(Certificate Pinning)与实践小结
证书锁定是什么意思
- 在「证书链被系统信任」之外,客户端额外要求:该域名的证书(或公钥)必须与 App 里预置的 pin 一致。
- 即:只认预置的证书/公钥,其他 CA 签的、系统信任的也不行。
- 攻击者即使拿到「看起来合法」的证书(CA 被攻破、设备被装恶意根证书),pin 对不上则连接被拒绝。
| 项目 | 说明 |
|---|---|
| Pin 什么 | 可以 pin 服务器证书本身、中间证书、或者公钥(或它们的哈希)。pin 公钥的好处是:证书到期续期时,只要公钥不变,不用改 App 里的 pin。 |
| 优点 | 即使有人伪造证书、或 CA 出问题、或用户装了恶意根证书,只要不在你的 pin 列表里,就连不上;适合金融、支付等高安全场景。 |
| 缺点 | 证书要换(续期、换 CA)时,pin 也要换,通常需要发新版本或通过配置更新;否则新证书对不上 pin,用户会连不上。 |
| 实践 | 提前在客户端配置多组 pin(例如当前证书 + 即将启用的新证书),轮换时先发一版带新 pin 的 App,再在服务端切证书,最后再撤掉旧 pin,避免「只 pin 一张」导致换证当天大批用户失败。 |
实践小结
- 服务端:用好证书、配全证书链、注意过期和吊销。
- 客户端:绝不忽略证书错误、不信任所有证书;高安全场景可加证书锁定并做好 pin 轮换。
- 再配合 HSTS、避免混合内容,整体安全性会高很多。
10.6 客户端(Android)HTTPS 使用要点
下面以 Android 为例,说明客户端在做 HTTPS 时要注意的证书校验、存储和错误处理。
| 项目 | 说明 |
|---|---|
| 证书存在哪、分几种 | Android 把证书分成两类: ① 系统信任存储:手机出厂时自带的一批可信 CA 根证书,应用只能读、不能改;HttpsURLConnection / OkHttp 默认就是用这里来验证服务器证书链。 ② 用户信任存储:用户自己在「设置 → 安全与隐私 → 加密与凭据 → 安装证书」里装的证书;装了之后,系统也会用它们参与 TLS 校验,所以用户装的根证书可以用来做抓包、企业代理等(等于信任了某个「中间人」)。 应用还可以自己维护一份私有证书(如放在 assets 或用 KeyStore),只给自定义的 TrustManager 或 network_security_config 用,不会进系统/用户的全局信任库。 |
| 默认会做什么校验 | 使用 HttpsURLConnection 或 OkHttp 时,默认会:一、用系统信任库验证服务器证书链;二、做主机名校验(你请求的域名必须和证书里的域名一致)。生产环境绝对不能关掉校验、或写成「信任所有证书/所有主机名」,否则很容易被中间人攻击。 |
| 自签名/内网怎么测 | 两种常见做法:一、把自签名 CA 或服务器证书装到用户信任存储,系统就会认;二、只在调试版里用自定义 TrustManager / SSLSocketFactory 信任你指定的证书,正式版必须去掉或用 BuildConfig 区分,避免正式包也信任自签名。 |
| 证书锁定怎么配 | 用 OkHttp 时通过 CertificatePinner.add("host", "sha256/Base64…") 为域名配置 pin;同一域名可以配多个 pin 做备份。换证书时先发一版带新 pin 的 App,再在服务端切证书,最后再删旧 pin。 |
| 网络安全配置(Android 7+) | 在 network_security_config.xml 里可以统一配置:信任哪些用户/系统证书、只允许哪些 pin、是否允许明文(cleartext)等;这样不用在代码里写死「信任所有」,可以按 debug/release 或渠道区分策略。 |
| 出错时怎么处理 | 遇到 SSLException、CertificateExpiredException(证书过期)、SSLPeerUnverifiedException(例如主机名对不上)等,要在界面上给用户明确提示(如「连接不安全」「证书已过期」),并打日志方便排查;不要静默吞掉异常,否则问题难定位。 |
小结
- 生产环境严格校验证书、不能信任所有;自签名只用于调试/内网,不带到正式包。
- 高安全场景可加证书锁定并做好 pin 轮换。
- 配合网络安全配置和清晰错误提示,安全又易维护。
常考点速览
便于面试/笔试前快速过一遍,只列关键词与结论,细节见正文。
| 大类 | 常考点 | 结论/口诀 |
|---|---|---|
| 分层 | HTTP/HTTPS 所在层 | 应用层;基于 TCP(80/443) |
| HTTP 特点 | 无状态、为什么用 TCP | 无状态:不记上次请求;用 TCP:要可靠、有序传报文 |
| 方法 | GET vs POST、幂等与安全 | GET 幂等且安全、参数在 URL、可缓存;POST 非幂等、数据在 body、不缓存。幂等:多次相同请求效果一致;安全:不改服务器状态 |
| 状态码 | 301 vs 302、401 vs 403、502/503/504 | 301 永久/302 临时;401 未认证/403 无权限;502 上游坏/503 本机过载/504 上游超时 |
| 缓存 | 强缓存 vs 协商缓存、命中顺序 | 强缓存不发请求(max-age/Expires);协商缓存发请求带条件头,304 用本地。顺序:先判强缓存是否有效 → 无效再协商 |
| 缓存头 | Cache-Control、ETag vs Last-Modified | Cache-Control 优先于 Expires;ETag 优先于 Last-Modified;no-cache 是「要验证」不是「不缓存」 |
| 连接 | 短/长连接、管道化 | 短连接一请求一连接;长连接复用(HTTP/1.1 默认);管道化依赖长连接、HTTP/1.1 有队头阻塞,少用;HTTP/2 多路复用解决 |
| Cookie/Session | 区别、SessionID 谁用 | Cookie 存客户端、Session 存服务端;SessionID 客户端只负责带给服务器,真正用的是服务器 |
| CORS | 同源/跨域、简单请求 vs 预检 | 同源=协议+域名+端口一致;跨域=任一项不同。简单请求不发 OPTIONS;非简单(自定义头、PUT/DELETE、application/json 等)先发 OPTIONS 预检 |
| HTTPS 流程 | 完整步骤 | DNS → TCP 三次握手(443)→ TLS 握手(证书+密钥交换)→ 加密 HTTP 请求/响应 |
| TLS | SSL vs TLS、握手几步 | SSL 与 TLS 分开用,现只用 TLS;握手:ClientHello → ServerHello+证书 → 校验证书 → 密钥交换 → Finished |
| 证书 | 链、验证项、CRL vs OCSP | 链:服务器证→中间证→根证,逐级验签;验证:链+有效期+域名+吊销;CRL 下载名单,OCSP 在线查,OCSP Stapling 由服务端带证明 |
| MITM | 怎么防、何时仍会破 | 用 HTTPS+严格校验证书;关校验、用户点继续、设备装恶意根证书时仍会破 |
| 证书锁定 | 是什么、pin 什么 | 只认预置的证书/公钥;pin 公钥利于轮换;换证要更新 pin,可多组 pin 平滑过渡 |
| Android | 证书存哪、禁止做什么 | 系统信任库+用户信任库;生产禁止关校验、禁止信任所有证书 |
小结
- HTTP:无状态、请求-响应、基于 TCP,通过方法、状态码、头部和缓存等组成完整 Web 协议。
- HTTPS:在 HTTP 上增加 TLS 加密与证书验证,是生产与敏感场景的标准选择。
- 实际应用中:正确使用状态码与头部、合理设置缓存与连接、在客户端(如 Android)严格校验证书并可选使用证书锁定,即可兼顾性能与安全。