📌PDF:大白话说Java面试题 — 09_Zookeeper篇
第2题:说一下什么是 Http 协议?
📚回答:
- 核心考点: HTTP 协议是互联网通信的基石,大厂面试中不会只问"应用层协议、请求响应模型",而是深入考察HTTP 各版本的演进差异(队头阻塞的解决、二进制分帧、QUIC 协议)、报文结构的字节级解析(请求行/状态行、Header 压缩、Chunked 传输)、状态码的语义与使用场景(2xx/3xx/4xx/5xx 的精确区分)、以及生产环境的性能优化(Keep-Alive 调优、HTTP/2 服务端推送、TLS 握手优化)。核心考察维度包括:协议演进、报文结构、状态码语义、连接管理、安全机制、性能优化。
1. HTTP 协议的本质与定位
HTTP(HyperText Transfer Protocol)是应用层协议,基于 TCP(HTTP/1.1、HTTP/2)或 UDP+QUIC(HTTP/3),采用请求-响应(Request-Response)模型,客户端主动发起请求,服务器被动返回响应。
OSI 七层模型中的位置:
应用层: HTTP / HTTPS / FTP / DNS │ ▼ 传输层: TCP (HTTP/1.1, HTTP/2) / UDP+QUIC (HTTP/3) │ ▼ 网络层: IP / ICMP │ ▼ 链路层: Ethernet / WiFiHTTP 的核心设计哲学:
- 简单性:文本协议,人类可读
- 可扩展性:Header 机制允许任意扩展
- 无状态性:每次请求独立,服务器不保存客户端状态(通过 Cookie/Session/Token 补偿)
- 统一接口:GET/POST/PUT/DELETE 等语义化方法
[citation:0]
2. HTTP 报文结构详解
- 2.1 请求报文(Request Message)
请求行 GET /api/users?page=1&size=20 HTTP/1.1 请求头 Host: api.example.com Accept: application/json Authorization: Bearer eyJhbGci... User-Agent: Mozilla/5.0... 空行 请求体 (GET 无请求体,POST/PUT 有)请求行结构:
<方法> <URI> <协议版本> │ │ │ │ │ └── HTTP/1.1 或 HTTP/2 │ └────────── /api/users?page=1&size=20 └───────────────── GET / POST / PUT / DELETE / PATCH / HEAD / OPTIONS常用方法语义:
| 方法 | 语义 | 幂等性 | 安全性 | 典型场景 |
|---|---|---|---|---|
| GET | 获取资源 | ✅ 幂等 | ✅ 安全 | 查询数据 |
| POST | 创建资源 | ❌ 不幂等 | ❌ 不安全 | 提交表单、创建订单 |
| PUT | 全量更新资源 | ✅ 幂等 | ❌ 不安全 | 更新用户信息 |
| PATCH | 部分更新资源 | ❌ 不幂等 | ❌ 不安全 | 修改用户昵称 |
| DELETE | 删除资源 | ✅ 幂等 | ❌ 不安全 | 删除订单 |
| HEAD | 获取响应头(无体) | ✅ 幂等 | ✅ 安全 | 检查资源是否存在 |
| OPTIONS | 获取支持的方法 | ✅ 幂等 | ✅ 安全 | CORS 预检请求 |
幂等性:多次执行结果相同。GET/PUT/DELETE 是幂等的,POST/PATCH 不是。
安全性:不改变服务器状态。GET/HEAD/OPTIONS 是安全的,其他不是。
[citation:1]
- 2.2 响应报文(Response Message)
状态行 HTTP/1.1 200 OK 响应头 Content-Type: application/json Content-Length: 256 Cache-Control: max-age=3600 Set-Cookie: sessionId=abc123; HttpOnly; Secure 空行 响应体 {"code":200,"data":{"id":1,"name":"Alice"}}状态行结构:
<协议版本> <状态码> <原因短语> │ │ │ │ │ └── OK / Not Found / Internal Server Error │ └─────────── 200 / 404 / 500 └───────────────────── HTTP/1.1 / HTTP/2- 2.3 状态码的精确语义
2xx 成功:
| 状态码 | 语义 | 使用场景 |
|---|---|---|
| 200 OK | 请求成功 | GET 查询成功、POST 创建成功(返回资源) |
| 201 Created | 资源创建成功 | POST 创建资源成功,响应头 Location 指向新资源 |
| 202 Accepted | 请求已接受,异步处理中 | 提交异步任务(如文件上传、批量处理) |
| 204 No Content | 请求成功,无返回体 | DELETE 删除成功、PUT 更新成功 |
| 206 Partial Content | 部分内容 | 断点续传、Range 请求 |
3xx 重定向:
| 状态码 | 语义 | 使用场景 |
|---|---|---|
| 301 Moved Permanently | 永久重定向 | 网站换域名,SEO 权重转移 |
| 302 Found | 临时重定向 | 登录后跳转、短链接 |
| 304 Not Modified | 缓存有效 | 协商缓存,客户端使用本地缓存 |
| 307 Temporary Redirect | 临时重定向(方法不变) | 302 的修正版,POST 重定向后仍用 POST |
| 308 Permanent Redirect | 永久重定向(方法不变) | 301 的修正版,POST 重定向后仍用 POST |
4xx 客户端错误:
| 状态码 | 语义 | 使用场景 |
|---|---|---|
| 400 Bad Request | 请求参数错误 | 参数缺失、格式错误、校验失败 |
| 401 Unauthorized | 未认证 | 未登录、Token 过期 |
| 403 Forbidden | 无权限 | 已登录但无访问权限 |
| 404 Not Found | 资源不存在 | URL 错误、资源已删除 |
| 409 Conflict | 资源冲突 | 并发修改冲突、唯一约束冲突 |
| 429 Too Many Requests | 请求过多 | 限流触发 |
| 422 Unprocessable Entity | 语义错误 | 参数格式正确但业务逻辑错误 |
5xx 服务器错误:
| 状态码 | 语义 | 使用场景 |
|---|---|---|
| 500 Internal Server Error | 服务器内部错误 | 未捕获异常、代码 Bug |
| 502 Bad Gateway | 网关错误 | Nginx 代理的后端服务不可用 |
| 503 Service Unavailable | 服务不可用 | 服务维护、过载保护 |
| 504 Gateway Timeout | 网关超时 | 后端服务响应超时 |
[citation:2]
3. HTTP 版本演进与核心差异
- 3.1 HTTP/1.0(1996)
特点:
- 每个请求/响应对需要独立的 TCP 连接
- 请求完成后立即关闭连接
问题:
请求 HTML 页面 ├── TCP 三次握手 ├── 发送 GET /index.html ├── 接收响应 └── TCP 四次挥手 请求 CSS 文件 ├── TCP 三次握手(再次!) ├── 发送 GET /style.css ├── 接收响应 └── TCP 四次挥手 请求 JS 文件 ├── TCP 三次握手(再次!) └── ... → 大量 TCP 握手/挥手开销,延迟高- 3.2 HTTP/1.1(1997)——持久连接与管道化
核心改进:
| 特性 | 说明 | 配置 |
|---|---|---|
| 持久连接(Keep-Alive) | 多个请求复用同一 TCP 连接 | Connection: keep-alive(默认开启) |
| 管道化(Pipelining) | 客户端可连续发送多个请求,无需等待响应 | 实际因队头阻塞问题很少使用 |
| 分块传输(Chunked) | 服务器边生成边发送,无需预先知道 Content-Length | Transfer-Encoding: chunked |
| 缓存控制 | 更精细的缓存策略 | Cache-Control、ETag、Last-Modified |
| Host 头 | 支持虚拟主机,同一 IP 多域名 | Host: api.example.com |
Keep-Alive 的队头阻塞(Head-of-Line Blocking):
HTTP/1.1 Keep-Alive 连接: 请求1: GET /api/a → 处理耗时 10s 请求2: GET /api/b → 处理耗时 1s 请求3: GET /api/c → 处理耗时 1s 虽然共用一个 TCP 连接,但响应必须按请求顺序返回! → 请求2和3必须等请求1完成后才能返回 → 队头阻塞:前面的慢请求阻塞后面的快请求解决方案:浏览器并行开启 6~8 个 TCP 连接(域名分片)。
- 3.3 HTTP/2(2015)——二进制分帧与多路复用
核心改进:
| 特性 | HTTP/1.1 | HTTP/2 | 效果 |
|---|---|---|---|
| 传输格式 | 文本 | 二进制分帧 | 更高效解析,错误率更低 |
| 多路复用 | 单连接串行 | 单连接并行多流 | 解决队头阻塞 |
| 头部压缩 | 无压缩 | HPACK 算法 | 减少重复 Header 传输 |
| 服务端推送 | 不支持 | 支持 | 服务器主动推送资源 |
| 流优先级 | 不支持 | 支持 | 优先传输关键资源 |
二进制分帧层:
HTTP/2 将请求/响应拆分为二进制帧: Stream 1 (请求 /index.html): HEADERS 帧: :method=GET, :path=/index.html DATA 帧: (空) Stream 3 (请求 /style.css): HEADERS 帧: :method=GET, :path=/style.css DATA 帧: (空) Stream 5 (请求 /script.js): HEADERS 帧: :method=GET, :path=/script.js DATA 帧: (空) → 三个 Stream 在同一个 TCP 连接上交错传输 → 互不阻塞,解决 HTTP/1.1 的队头阻塞HPACK 头部压缩:
请求1: GET /page1 Host: api.example.com Accept: application/json Authorization: Bearer eyJhbGciOiJIUzI1NiIs... 请求2: GET /page2 Host: api.example.com ← 静态表索引,1 字节 Accept: application/json ← 静态表索引,1 字节 Authorization: Bearer ... ← 动态表索引,1 字节 → 后续请求 Header 只需几个字节!但 HTTP/2 仍有 TCP 层队头阻塞:
HTTP/2 多路复用在一个 TCP 连接上: Stream 1 的帧丢失 → TCP 重传 → 所有 Stream 等待 → TCP 层队头阻塞:一个 Stream 的丢包阻塞所有 Stream[citation:3]
- 3.4 HTTP/3(2022)——基于 QUIC 协议
核心改进:
| 特性 | HTTP/2 | HTTP/3 | 效果 |
|---|---|---|---|
| 传输层 | TCP + TLS | QUIC (UDP + TLS 1.3) | 减少握手延迟 |
| 队头阻塞 | TCP 层存在 | 无(基于 UDP) | 彻底解决 |
| 连接迁移 | 不支持 | 支持(连接 ID) | 网络切换不中断 |
| 握手延迟 | 2-3 RTT | 0-1 RTT | 首次连接更快 |
| 拥塞控制 | TCP 内核实现 | 用户空间实现 | 更灵活,快速迭代 |
QUIC 的 0-RTT 握手:
HTTP/2 (TCP + TLS 1.2): TCP 三次握手: 1 RTT TLS 握手: 2 RTT 总: 3 RTT 后才能发送请求 HTTP/3 (QUIC + TLS 1.3): 首次连接: 1 RTT (QUIC 握手内含 TLS 1.3) 后续连接: 0 RTT (使用之前会话的密钥) → 首次请求发送时间减少 67%连接迁移:
HTTP/2 (TCP): 手机从 WiFi 切换到 4G → IP 变化 → TCP 连接断开 → 重新建立连接 HTTP/3 (QUIC): 手机从 WiFi 切换到 4G → IP 变化 → 连接 ID 不变 → 继续传输 → 网络切换无感知| 版本 | 连接建立 | 队头阻塞 | 头部压缩 | 多路复用 | 连接迁移 | 适用场景 |
|---|---|---|---|---|---|---|
| HTTP/1.0 | 3 RTT/请求 | 无(单请求) | 无 | 无 | ❌ | 已淘汰 |
| HTTP/1.1 | 3 RTT 首次,后续复用 | 应用层 | 无 | 单连接串行 | ❌ | 兼容老旧系统 |
| HTTP/2 | 3 RTT 首次,后续复用 | TCP 层 | HPACK | 单连接并行 | ❌ | 当前主流 |
| HTTP/3 | 1 RTT 首次,0 RTT 后续 | 无 | QPACK | 单连接并行 | ✅ | 移动端、高延迟网络 |
[citation:4]
4. HTTP 安全机制
- 4.1 HTTPS = HTTP + TLS/SSL
HTTP HTTPS │ │ ▼ ▼ TCP 80 TLS/SSL │ ▼ TCP 443TLS 1.2 握手(2-RTT):
Client → Server: ClientHello (支持的加密套件、随机数) Client ← Server: ServerHello (选定加密套件、随机数、证书) Client → Server: ClientKeyExchange (预主密钥加密传输) Client ← Server: Finished (握手完成) → 2 RTT 后才能发送应用数据TLS 1.3 握手(1-RTT):
Client → Server: ClientHello + KeyShare (直接发送公钥) Client ← Server: ServerHello + EncryptedExtensions + Finished → 1 RTT 后发送应用数据 → 支持 0-RTT 模式(使用之前会话的 PSK)- 4.2 HSTS(HTTP Strict Transport Security)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload作用:
强制浏览器使用 HTTPS 访问,禁止 HTTP
防止 SSL 剥离攻击(中间人强制降级到 HTTP)
4.3 CSP(Content Security Policy)
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src *作用:
- 限制页面加载资源的来源,防止 XSS 攻击
default-src 'self':默认只允许同源资源script-src:限制 JS 来源img-src *:允许任意来源图片
[citation:5]
5. HTTP 性能优化
- 5.1 连接层优化
| 优化手段 | 配置 | 效果 |
|---|---|---|
| Keep-Alive 超时调优 | KeepAliveTimeout 65 | 减少 TCP 握手开销 |
| TCP Fast Open | 内核参数tcp_fastopen=3 | 减少 1 RTT |
| TLS 1.3 | 升级 OpenSSL/Nginx | 减少 1 RTT |
| HTTP/2 Server Push | Link: </style.css>; rel=preload; as=style | 服务器主动推送关键资源 |
| HTTP/3 | 升级 Nginx/Cloudflare | 彻底解决队头阻塞 |
- 5.2 应用层优化
| 优化手段 | 实现 | 效果 |
|---|---|---|
| Gzip/Brotli 压缩 | Content-Encoding: br | 减少 70%~80% 传输体积 |
| 缓存策略 | Cache-Control: max-age=31536000, immutable | 减少重复请求 |
| CDN 分发 | 边缘节点缓存静态资源 | 减少源站压力,降低延迟 |
| 域名分片 | 静态资源使用独立域名 | 突破浏览器 6~8 连接限制 |
| 资源合并 | CSS/JS 合并、雪碧图 | 减少请求数 |
- 5.3 Nginx HTTP/2 配置示例
server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; # HTTP/2 Server Push location = /index.html { add_header Link "</style.css>; rel=preload; as=style" always; add_header Link "</app.js>; rel=preload; as=script" always; } # Brotli 压缩 brotli on; brotli_types text/plain text/css application/json application/javascript; # 缓存控制 location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } }[citation:6]
6. 面试官追问与高分回答模板
- 追问 1:“说一下 HTTP 协议?”
低分回答:“HTTP 是应用层协议,基于请求响应模型,无状态。”(太浅)
高分回答:
"HTTP 是应用层协议,基于 TCP(HTTP/1.1、HTTP/2)或 UDP+QUIC(HTTP/3),采用请求-响应模型。
核心特点:
- 无状态:每次请求独立,服务器不保存客户端状态,通过 Cookie/Session/Token 补偿。
- 统一接口:GET(获取)、POST(创建)、PUT(全量更新)、PATCH(部分更新)、DELETE(删除)等方法语义明确。
- 可扩展:Header 机制允许任意扩展,如 Authorization、Cache-Control 等。
版本演进:HTTP/1.0 短连接 → HTTP/1.1 Keep-Alive(仍有队头阻塞) → HTTP/2 二进制分帧+多路复用(解决应用层队头阻塞,但 TCP 层仍存在) → HTTP/3 QUIC(基于 UDP,彻底解决队头阻塞,支持连接迁移)。"
- 追问 2:“HTTP/1.1 的队头阻塞是什么?HTTP/2 怎么解决的?HTTP/3 又解决了什么?”
高分回答:
"HTTP/1.1 的队头阻塞是应用层的:Keep-Alive 连接上,响应必须按请求顺序返回。如果第一个请求处理慢(如 10 秒),后面的请求即使处理快(如 1 秒)也必须等待。
HTTP/2 通过二进制分帧 + 多路复用解决应用层队头阻塞:将请求/响应拆分为二进制帧,多个 Stream 在同一个 TCP 连接上交错传输,互不阻塞。
但 HTTP/2 仍有TCP 层队头阻塞:一个 Stream 的帧丢失,TCP 重传会阻塞所有 Stream。
HTTP/3 基于QUIC 协议(UDP + TLS 1.3)彻底解决:
- QUIC 在应用层实现可靠传输,每个 Stream 独立拥塞控制和重传
- 一个 Stream 丢包不影响其他 Stream
- 支持 0-RTT 握手和连接迁移(网络切换不中断)"
- 追问 3:“GET 和 POST 有什么区别?”
高分回答:
"GET 和 POST 的核心区别在语义和使用场景,而非传参方式:
- 语义:GET 是获取资源,POST 是创建资源。GET 是安全且幂等的,POST 不是。
- 缓存:GET 请求可被浏览器缓存,POST 默认不缓存。
- 书签/历史:GET URL 可被收藏和分享,POST 不能。
- 参数位置:GET 参数在 URL(有长度限制,约 2KB~8KB),POST 参数在 Body(无限制)。
- 幂等性:GET 多次执行结果相同,POST 多次执行可能创建多个资源。
常见误区:
- ‘GET 参数在 URL,POST 在 Body’ → 技术上 GET 也可以有 Body(虽然不推荐),POST 也可以有 URL 参数
- ‘POST 比 GET 安全’ → 都不安全,HTTPS 才安全
实际选型:获取数据用 GET,创建/提交数据用 POST。"
- 追问 4:“301 和 302 有什么区别?什么时候用 307 和 308?”
高分回答:
"301 和 302 的核心区别在于永久性和方法保留:
- 301 Moved Permanently:永久重定向,SEO 权重转移到新 URL。但某些客户端会将 POST 改为 GET(历史遗留问题)。
- 302 Found:临时重定向,SEO 权重保留在原 URL。同样存在 POST 变 GET 的问题。
- 307 Temporary Redirect:302 的修正版,强制保留请求方法。POST 重定向后仍是 POST。
- 308 Permanent Redirect:301 的修正版,强制保留请求方法。POST 重定向后仍是 POST。
使用建议:- 永久重定向且需要保留方法 → 308
- 临时重定向且需要保留方法 → 307
- 兼容老旧客户端 → 301/302"
- 追问 5:“HTTPS 的握手过程是怎样的?TLS 1.3 相比 1.2 有什么改进?”
高分回答:
"TLS 1.2 握手需要 2 RTT:
- ClientHello (支持的加密套件、随机数)
- ServerHello + Certificate + ServerKeyExchange
- ClientKeyExchange (预主密钥加密传输)
- Finished
→ 2 RTT 后才能发送应用数据。
TLS 1.3 改进:- 1-RTT 握手:ClientHello 直接包含 KeyShare(公钥),ServerHello 返回选定参数,1 RTT 后发送数据。
- 0-RTT 模式:使用之前会话的 PSK(Pre-Shared Key),首次请求 0 RTT。
- 简化加密套件:从 1.2 的数十种减少到 1.3 的 5 种,减少协商复杂度。
- 前向安全:即使长期私钥泄露,历史会话也不受影响。
HTTP/3 的 QUIC 将 TLS 1.3 集成到握手过程中,实现 0-RTT 或 1-RTT 的首次请求。"
- 追问 6:“HTTP/2 的服务端推送是什么?有什么使用场景和限制?”
高分回答:
"HTTP/2 Server Push 允许服务器在客户端请求 HTML 时,主动推送 CSS、JS 等关键资源,减少客户端解析 HTML 后再发请求的时间。
使用场景:
- 推送首屏关键 CSS/JS,减少渲染阻塞
- 推送 API 预加载数据(如用户登录后推送个人配置)
限制:- 浏览器可能已缓存该资源,推送浪费带宽
- 推送资源必须与主请求同源
- 优先级控制复杂,可能推送非关键资源
- 部分浏览器(如 Safari)已禁用 Server Push
替代方案:Link: <url>; rel=preload头:客户端收到后主动请求,比 Server Push 更可控- 资源内联:将关键 CSS/JS 直接嵌入 HTML,减少请求数"
7. 方案选型速查表
| 场景 | 推荐协议/配置 | 核心理由 |
|---|---|---|
| 传统 Web 应用 | HTTP/2 + TLS 1.3 | 当前主流,兼容性好 |
| 移动端/高延迟网络 | HTTP/3 (QUIC) | 0-RTT,连接迁移,抗丢包 |
| 内部微服务通信 | HTTP/2 + gRPC | 二进制协议,高效序列化 |
| 静态资源 CDN | HTTP/2 + Brotli | 压缩率高,多路复用 |
| API 网关 | HTTP/2 + 限流 | 高并发,连接复用 |
| 实时通信 | WebSocket / HTTP/3 | 低延迟,全双工 |
| 遗留系统兼容 | HTTP/1.1 | 兼容性优先 |
💡面试官想要的满分总结:
HTTP 协议是互联网通信的基石,理解它必须抓住版本演进、报文语义、性能瓶颈三个维度:
版本演进:HTTP/1.0 短连接 → HTTP/1.1 Keep-Alive(应用层队头阻塞) → HTTP/2 二进制分帧+多路复用(解决应用层队头阻塞,TCP 层仍存在) → HTTP/3 QUIC(基于 UDP,彻底解决队头阻塞,0-RTT,连接迁移)。
报文语义:方法(GET/POST/PUT/PATCH/DELETE)的幂等性和安全性是设计 RESTful API 的基础。状态码的精确使用(201 Created、202 Accepted、409 Conflict、422 Unprocessable Entity)体现 API 设计的专业性。
性能优化:连接层(Keep-Alive、TLS 1.3、HTTP/3)、应用层(HPACK/QPACK 压缩、缓存策略、CDN)、安全层(HSTS、CSP)三个层面综合优化。
最后记住:HTTP 是无状态的应用层协议,状态管理通过 Cookie/Session/Token 补偿。HTTPS 不是单独的协议,而是 HTTP over TLS。HTTP/2 的多路复用解决了应用层队头阻塞,但 TCP 层队头阻塞需要 HTTP/3 的 QUIC 才能彻底解决。
觉得对您有帮助,麻烦点点关注啦,您的关注是我创作的最大动力~ 🎯