HTTP 请求是怎么走的:从 Android 页面到服务端响应

在 Android 页面里调用一次接口,日志只留下 GET /articles/42 和 200。页面第二次打开却更快,抓包偶尔出现 304;换成弱网后,请求可能连状态码都没有。它们是同一条请求链上的不同结果,光记"HTTP 是超文本传输协议"解释不了。

一句话结论:HTTP 规定客户端如何表达请求、服务端如何表达结果,以及缓存如何复用结果;一次请求是否建新连接、是否传回响应体,还要看缓存状态、连接复用和所用的 HTTP 版本。

本文以 Android App 读取一篇文章为例,按 RFC 9110--9114 的协议语义解释主线。Android 落点参考平台网络文档与 OkHttp 的公开说明。下文的报文是教学示意,不是某个真实接口的抓包;先不展开 DNS、TLS 握手细节、代理实现和 QUIC 拥塞控制。

1. 先看全局:一次请求有哪些参与者?

text 复制代码
页面发起读取
  → HTTP 客户端构造请求
  → 本地缓存判断能否直接复用
  → 需要联网时,选择已有连接或建立连接
  → 服务端处理目标资源
  → 返回状态、首部与可选的响应内容
  → 客户端处理缓存并把结果交回页面

这张图是概念流程。页面通常交给网络库一个 URL、方法和可选的请求体;网络库负责报文编码、连接管理和响应读取。缓存既可能直接给出结果,也可能让客户端带着校验条件去问服务端。服务端决定资源的表示、状态码和缓存指令。最终页面需要处理的是成功数据、业务错误或网络失败,而不是自己拼装 TCP 字节。

HTTP 在应用层定义"要对哪个资源做什么"和"结果是什么"。https:// 表示这次 HTTP 通信受到 TLS 保护;它并没有把 GET、状态码、缓存这些 HTTP 语义换掉。至于线上字节怎样组织,要看 HTTP/1.1、HTTP/2 或 HTTP/3。

2. 一次请求和响应,分别写了什么?

先把下面的例子当成 HTTP/1.1 的可读示意。真实报文还会有其他首部,HTTPS 下也不能直接从普通网络抓包中读到这些明文。

http 复制代码
GET /articles/42 HTTP/1.1
Host: api.example.com
Accept: application/json

请求行给出方法、目标路径和协议版本;Host 指向目标主机,Accept 表示客户端愿意接收 JSON。空行结束首部。这个 GET 没有请求体,并不代表所有请求都没有请求体。HTTP/1.1 的起始行、首部、空行与可选消息体结构由 RFC 9112 定义。

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: private, max-age=60
ETag: "article-42-v7"

{"id":42,"title":"HTTP 入门"}

响应的 200 表示请求成功;Content-Type 告诉客户端怎样理解内容。这里服务端允许私有缓存 在新鲜期内复用响应,并给出 ETag 作为以后校验版本的标识。max-age=60 是这条示意响应的 60 秒新鲜期,不是 HTTP 的统一默认值。

有一个层级细节:上面的文字格式只用于讲 HTTP/1.1。HTTP/2 和 HTTP/3 继续承载方法、路径、状态码与首部等语义,但线上使用帧与流,不能把这段文本当作它们的实际线格式。RFC 9110 定义通用语义,RFC 9113 与 RFC 9114 分别定义后两种映射。

3. 方法和状态码该怎样读?

读请求时,我会先看方法是否符合业务意图,再看响应状态。常见方法可以这样记:

方法 约定的意图 排查时要注意
GET 获取目标资源的表示 按协议语义是安全且幂等的;不要用它触发转账、下单等状态改变。
POST 让目标资源处理提交的内容 常用于创建或执行操作;不能仅凭方法推断重试安全。
PUT 用提交的表示创建或替换目标资源的状态 按协议语义幂等,但相同请求的响应不一定每次相同。
DELETE 删除目标资源与其当前功能的关联 按协议语义幂等,不等于每次都返回相同状态码。

"幂等"说的是重复同一请求的预期服务端效果 与执行一次相同,不是"绝不会写日志",也不是"每次都返回相同字节"。因此,连接中途断开时,客户端能否自动重试,首先取决于方法语义和接口自身的设计。特别是支付、下单一类 POST,应由业务提供幂等键或明确的去重机制,再决定重试策略。RFC 9110 的方法语义 对安全和幂等有严格定义。

状态码也先按类别读,再看具体含义:

类别 常见例子 给 Android 端的信号
2xx 成功 200、201、204 204 已成功但没有响应内容,不要强行按 JSON 解析。
3xx 重定向或缓存协商 301、302、304 304 表示本地已有的表示仍可用,通常配合条件请求。
4xx 请求侧问题 400、401、404、429 需要结合接口契约处理;重复原样请求未必有用。
5xx 服务端问题 500、503 可考虑有边界的重试,但仍要看操作是否可安全重复。

表中的处理建议是实践建议,不是状态码本身自动替 App 完成的行为。尤其要把"收到 HTTP 错误响应"和"根本没收到 HTTP 响应"分开:DNS 失败、TLS 校验失败、超时或断网时,通常没有可供读取的 HTTP 状态码。

4. 第二次打开页面,为什么可能没有新内容传回来?

继续看 /articles/42。如果客户端确实配置并保存了可用缓存,在示意响应仍新鲜时,可以直接使用缓存表示,不发网络请求。过了新鲜期,也未必需要重新下载正文。客户端可带上先前的实体标签:

http 复制代码
GET /articles/42 HTTP/1.1
Host: api.example.com
If-None-Match: "article-42-v7"

服务端确认表示没变时,可能回复 304 Not Modified,不再传输那份正文。客户端用已保存的表示完成读取。所以 304 有网络往返,但没有重复下载表示内容 ;它和完全离线的缓存命中不是一回事。RFC 9110 对 304 的定义 与 RFC 9111 的缓存规则 是这条路径的依据。

指令或字段 这里要读出的意思
Cache-Control: max-age=60 在指定的新鲜期内可以按缓存规则复用。
Cache-Control: no-cache 可以存储,但复用前通常需要向源站验证。
Cache-Control: no-store 缓存不得存储这次响应。
Cache-Control: private 共享缓存不能存;符合条件的私有缓存可以存。
ETag / If-None-Match 一端给出版本标识,另一端用它发条件请求。

这里还有一个 Android 常见误判:服务端发了 Cache-Control,不等于 App 的网络库已经开启磁盘缓存。OkHttp 的 Cache 是可选且默认关闭 的;只有配置了缓存,才谈得上它的本地缓存命中与条件校验。缓存策略也不能替代敏感数据的存储保护。OkHttp 缓存文档 明确说明了默认状态与命中路径。

5. HTTP/1.1、HTTP/2、HTTP/3 改了哪一层?

三个版本共享 HTTP 的核心语义,主要差别在消息怎样在连接上传输。

版本 消息传输方式 常见底层路径 直观影响
HTTP/1.1 文本起始行和首部;连接可复用 通常是 TCP,HTTPS 时再加 TLS 多次请求可以复用连接,但协议本身没有 HTTP/2 那样的流多路复用层。
HTTP/2 二进制帧与多路复用流 通常是 TLS over TCP 同一连接上可并发承载多个请求;底层 TCP 丢包仍可能影响该连接的其他流。
HTTP/3 在 QUIC 流上承载 HTTP 帧 QUIC 基于 UDP,并集成 TLS 1.3 握手 不同流的可靠传输由 QUIC 管理,减少 TCP 层丢包造成的跨流阻塞。

这不是"版本越高,单个接口一定越快"的承诺。真实耗时还取决于连接是否复用、服务端处理、网络丢包、缓存和客户端实现。排查时先确认实际协商出的协议版本 ,别看到代码里的 https:// 就推断一定用了 HTTP/2 或 HTTP/3。RFC 9113 与 RFC 9114 分别描述了 HTTP/2 多路复用和 HTTP/3 的 QUIC 映射。

6. 回到 Android:看到慢请求或失败,先查哪里?

我的排查顺序是先分清有没有响应,再研究响应内容。没有状态码,就从设备网络、DNS、连接、TLS、超时和取消查起;拿到状态码后,再看方法、目标 URL、关键首部、服务端返回和缓存命中情况。这样的顺序比一上来把所有失败都归成"接口 500"有效。

Android 端还要守住几个边界:

  • Manifest 需要 INTERNET 权限;网络 I/O 不应放在主线程。平台文档说明,主线程做网络操作会触发 NetworkOnMainThreadException。Android 网络连接指南
  • 生产请求优先用 HTTPS,并正确验证证书。面向 Android 9(API 28)及以上版本的应用默认限制明文流量;不要为调通一个测试接口就全局放开明文。Android 明文流量说明
  • 连接池复用的是连接 ,缓存复用的是响应表示。关闭或读完响应体、取消不再需要的调用,和缓存配置都属于客户端资源管理;具体 API 取决于所用网络库。
  • 把 HTTP 4xx/5xx、业务 JSON 中的错误码与 I/O 异常分开记录。它们发生在不同层,决定了提示、重试和排查方向。

回头看开头的现象:第二次打开更快,可能是连接复用,也可能是缓存命中;看到 304,说明至少发生了一次条件请求;连状态码都没有,则先检查 HTTP 响应生成之前的链路。抓住"语义、缓存、传输"这三层,就能把一次 HTTP 请求从页面一直追到结果。

参考规范与文档

相关推荐
0+1111 小时前
Linux --HTTPS协议原理
网络协议·http·https
hellojackjiang20111 小时前
IM聊天不掉线?生产级WebSocket断线重连、心跳保活实战
websocket·网络协议·网络编程·html5·即时通讯·im
码上上班1 小时前
HTTP知识点
网络·网络协议·http
无线图传-HDMI视频延长传输2 小时前
AM8962DT/AM8962DR:4K60 ProAV over IP 芯片方案,35ms 超低延迟 + 过交换机一对多+KVM 透传
网络·网络协议·tcp/ip
0+1112 小时前
Linux --HTTP Cookie 与 Session
网络·网络协议·http
牛战士coding2 小时前
如何让 Claude Desktop 与 Cursor 调用订单工具?MCP Streamable HTTP 接入思路
网络·网络协议·http
北城笑笑2 小时前
Server 18 ,Nginx 双服务器 HTTP转HTTPS 代理实战( HTTP 地址换 HTTPS 域名 )
运维·服务器·前端·后端·nginx·http·https
硅基造物主3 小时前
18.从 IP 到 MQTT:STM32 用 AT 指令驱动 ESP-12F 上云的完整链路(含全套实战代码 + 踩坑清单)
网络·stm32·单片机·嵌入式硬件·网络协议·tcp/ip
美狐美颜SDK开放平台3 小时前
直播APP平台搭建需要哪些技术?视频美颜SDK只是其中一环
android·ios·音视频·直播美颜sdk·视频美颜sdk