HTTP协议和HTTPS协议结合天气获取案例介绍

可以,HTTP/HTTPS 对嵌入式很重要。你可以先这样理解:

text 复制代码
HTTP  = 应用层协议,规定"请求怎么写、响应怎么回"
HTTPS = HTTP + TLS 加密层

也就是说,HTTPS 不是另一个完全不同的业务协议 ,它本质上还是 HTTP,只是 HTTP 数据在发出去前先经过 TLS 加密,防止被偷看、篡改、伪造。TLS 1.3 标准里也明确说明,TLS 的目标就是让客户端/服务器通信具备防窃听、防篡改、防伪造能力。(IETF Datatracker)


1. HTTP 在协议栈里的位置

以 ESP32 获取天气为例:

text 复制代码
你的应用代码
    ↓
HTTP 协议
    ↓
TCP
    ↓
IP
    ↓
Wi-Fi / 以太网 / 4G
    ↓
物理层

如果是 HTTPS:

text 复制代码
你的应用代码
    ↓
HTTP 协议
    ↓
TLS / SSL 加密层
    ↓
TCP
    ↓
IP
    ↓
Wi-Fi / 以太网 / 4G
    ↓
物理层

所以:

text 复制代码
HTTP  常用端口:80
HTTPS 常用端口:443

2. HTTP 是干啥的?

HTTP 的核心模型是:

text 复制代码
客户端请求,服务器响应

比如 ESP32 获取天气:

text 复制代码
ESP32  --->  天气服务器
请求:我想要大阪今天的天气

天气服务器  --->  ESP32
响应:温度 24℃,多云

HTTP 不是负责 Wi-Fi 连接的,也不是负责 IP 寻址的。它只负责规定应用层数据怎么组织。

可以把它理解成:

text 复制代码
TCP/IP 负责把字节送过去
HTTP  规定这些字节代表什么意思

HTTP 标准把 GET、POST、PUT、DELETE、状态码、头字段等语义统一定义出来;例如 GET 成功返回 200 时,响应内容通常表示目标资源的内容。(RFC 编辑器)


3. HTTP 请求格式

HTTP/1.1 的消息结构大概是:

text 复制代码
请求行
请求头
空行
请求体,可选

标准 HTTP/1.1 消息就是由 start-line、若干 header field、空行、可选 message body 组成。(RFC 编辑器)

例如 ESP32 请求天气:

http 复制代码
GET /data/2.5/weather?q=Osaka&appid=你的APIKEY&units=metric HTTP/1.1
Host: api.openweathermap.org
User-Agent: ESP32
Connection: close

注意最后有一个空行,表示 HTTP 头结束。

拆开看:

text 复制代码
GET

表示请求方法:我要获取资源。

text 复制代码
/data/2.5/weather?q=Osaka&appid=xxx&units=metric

表示请求路径和参数。

text 复制代码
HTTP/1.1

表示使用 HTTP/1.1 协议格式。

text 复制代码
Host: api.openweathermap.org

表示我要访问的主机名。

text 复制代码
Connection: close

表示请求结束后可以关闭 TCP 连接。


4. HTTP 响应格式

服务器返回:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 85
Connection: close

{
  "weather":[{"main":"Clouds"}],
  "main":{"temp":24.6,"humidity":60}
}

响应结构:

text 复制代码
状态行
响应头
空行
响应体

比如:

text 复制代码
HTTP/1.1 200 OK

表示请求成功。

常见状态码:

状态码 含义
200 成功
201 创建成功
204 成功,但没有响应体
301 / 302 重定向
400 请求格式错误
401 未认证
403 没权限
404 资源不存在
500 服务器内部错误

HTTP 状态码是 3 位数字,第一位表示大类:1xx 信息、2xx 成功、3xx 重定向、4xx 客户端错误、5xx 服务端错误。(RFC 编辑器)


5. GET 和 POST 的区别

嵌入式里最常用的是 GET 和 POST。

GET:获取数据

比如获取天气:

http 复制代码
GET /weather?city=Osaka HTTP/1.1
Host: api.xxx.com

特点:

text 复制代码
参数通常放在 URL 里
一般用于读取数据
请求体通常为空
适合获取天气、查询设备配置、下载小文件

POST:提交数据

比如设备上传温度:

http 复制代码
POST /api/device/upload HTTP/1.1
Host: cloud.xxx.com
Content-Type: application/json
Content-Length: 31

{"temp":25.6,"humidity":60}

特点:

text 复制代码
数据一般放在 body 里
适合上传数据、提交表单、登录、设备上报

6. HTTP 通信完整流程

以 HTTP 获取天气为例:

text 复制代码
1. ESP32 连接 Wi-Fi
2. DNS 解析域名
3. 建立 TCP 连接
4. 发送 HTTP GET 请求
5. 服务器处理请求
6. 服务器返回 HTTP 响应
7. ESP32 解析响应头和 JSON 数据
8. 关闭连接或保持连接

流程图:

text 复制代码
ESP32                         DNS服务器                   天气服务器
  │                              │                            │
  │ 查询 api.xxx.com 的 IP        │                            │
  │─────────────────────────────>│                            │
  │ 返回 IP 地址                  │                            │
  │<─────────────────────────────│                            │
  │                                                           │
  │ TCP 三次握手                                               │
  │──────────────────────────────────────────────────────────>│
  │                                                           │
  │ HTTP GET 请求                                              │
  │──────────────────────────────────────────────────────────>│
  │                                                           │
  │ HTTP 响应 JSON                                             │
  │<──────────────────────────────────────────────────────────│
  │                                                           │
  │ 关闭 TCP 或保持连接                                        │

7. HTTPS 比 HTTP 多了什么?

HTTPS 多了 TLS 加密层。

HTTP 明文传输时,网络中间的人理论上能看到:

text 复制代码
请求了哪个路径
请求头
请求体
响应内容
API Key
用户名密码
设备 Token

HTTPS 会把 HTTP 内容加密后再传。

所以别人抓包看到的大概是:

text 复制代码
一堆加密后的二进制数据

HTTPS 解决三个核心问题:

text 复制代码
1. 加密:别人看不懂数据
2. 防篡改:别人改了数据会被发现
3. 身份认证:确认你连的是正确服务器,不是假服务器

TLS 标准明确目标就是防止窃听、篡改和消息伪造。(IETF Datatracker)


8. HTTPS 通信流程

HTTPS 比 HTTP 多了 TLS 握手。

text 复制代码
1. ESP32 连接 Wi-Fi
2. DNS 解析域名
3. 建立 TCP 连接
4. TLS 握手
   - 协商 TLS 版本
   - 协商加密算法
   - 服务器发送证书
   - 客户端验证证书
   - 双方生成会话密钥
5. 用会话密钥加密 HTTP 请求
6. 服务器解密并处理
7. 服务器加密 HTTP 响应
8. ESP32 解密响应

流程图:

text 复制代码
ESP32                                             HTTPS服务器
  │                                                   │
  │ TCP 三次握手                                      │
  │─────────────────────────────────────────────────>│
  │                                                   │
  │ TLS ClientHello                                   │
  │─────────────────────────────────────────────────>│
  │ TLS ServerHello + 证书 + 密钥协商                  │
  │<─────────────────────────────────────────────────│
  │ 客户端验证证书,生成密钥                            │
  │─────────────────────────────────────────────────>│
  │                                                   │
  │ 加密后的 HTTP GET                                  │
  │─────────────────────────────────────────────────>│
  │                                                   │
  │ 加密后的 HTTP 响应                                 │
  │<─────────────────────────────────────────────────│

9. HTTP 和 HTTPS 速度差别

很多新手会觉得:

text 复制代码
HTTPS 一定比 HTTP 慢很多

实际要分情况看。

9.1 第一次连接:HTTPS 更慢

因为 HTTPS 多了 TLS 握手。

HTTP 第一次请求大概需要:

text 复制代码
DNS 查询
TCP 三次握手
HTTP 请求/响应

HTTPS 第一次请求大概需要:

text 复制代码
DNS 查询
TCP 三次握手
TLS 握手
加密后的 HTTP 请求/响应

所以第一次访问时,HTTPS 的首包延迟通常更高。


9.2 连接建立后:HTTPS 不一定慢很多

一旦 TLS 握手完成,后面的 HTTP 数据只是加密后传输。

对大多数场景来说,真正影响速度的是:

text 复制代码
网络带宽
网络延迟
丢包率
服务器响应速度
TCP 窗口
Wi-Fi 信号质量
设备 CPU 性能

而不是 "HTTP 还是 HTTPS" 本身。

ESP32 这种 MCU 上,HTTPS 的确会多消耗:

text 复制代码
RAM
Flash
CPU
握手时间
证书校验时间

但如果只是获取天气、上传 JSON、OTA 升级,通常完全能接受。


10. 通信速度、带宽、延迟分别是啥?

这三个概念要分清。

10.1 带宽 Bandwidth

带宽表示链路最大传输能力。

比如:

text 复制代码
10 Mbps
100 Mbps
300 Mbps

它像水管粗细。

水管越粗,理论上单位时间能流过的数据越多。


10.2 延迟 Latency

延迟表示数据从你这里到服务器再回来要多久。

常见用 RTT 表示:

text 复制代码
RTT = Round Trip Time = 往返时间

比如:

text 复制代码
ESP32 → 服务器 → ESP32

用了 80 ms,那么 RTT 大概是 80 ms。

延迟像"路有多远"。


10.3 吞吐量 Throughput

吞吐量是实际传输速度。

比如你的 Wi-Fi 标称 100 Mbps,但实际下载只有:

text 复制代码
20 Mbps

那实际吞吐量就是 20 Mbps。

它会受很多因素影响:

text 复制代码
信号强度
路由器性能
服务器限速
TCP 拥塞控制
丢包重传
协议开销
MCU 处理速度

11. 一个简单估算公式

传输一个文件大概耗时:

text 复制代码
总耗时 ≈ 连接建立时间 + 请求响应延迟 + 数据大小 / 实际吞吐量

比如下载 1 MB OTA 固件:

text 复制代码
固件大小:1 MB ≈ 8 Mbit
实际吞吐量:4 Mbps

理论纯传输时间:

text 复制代码
8 Mbit / 4 Mbps = 2 秒

但实际可能是:

text 复制代码
2 秒 + DNS + TCP握手 + TLS握手 + 服务器响应 + Flash写入时间

所以 ESP32 OTA 可能不是单纯网络传输慢,也可能是:

text 复制代码
Flash 写入慢
HTTPS 握手慢
证书验证慢
服务器响应慢
Wi-Fi 信号差

12. HTTP/1.1、HTTP/2、HTTP/3 速度差别

现在常见 HTTP 有几个版本:

text 复制代码
HTTP/1.1
HTTP/2
HTTP/3

它们的业务语义类似,比如 GET、POST、状态码这些概念都还在,但底层传输方式不同。


12.1 HTTP/1.1

特点:

text 复制代码
文本格式
简单直观
嵌入式最容易手写
一个 TCP 连接上并发能力较弱

HTTP/1.1 报文长这样:

http 复制代码
GET /index.html HTTP/1.1
Host: example.com

优点:

text 复制代码
简单
容易调试
可以用 socket 直接手写
适合 MCU 新手学习

缺点:

text 复制代码
请求头偏大
并发效率不高
多个资源请求可能要多个连接

HTTP/3 的标准文档也提到,HTTP/1.1 使用可读的文本字段,但没有多路复用层,通常需要多个 TCP 连接并行处理请求,这对拥塞控制和网络效率有负面影响。(RFC 编辑器)


12.2 HTTP/2

HTTP/2 不再是纯文本报文,而是二进制帧。

它的优势:

text 复制代码
一个 TCP 连接里可以并发多个请求
头部压缩
减少连接数量
延迟更低

适合网页这种场景:

text 复制代码
一个网页要加载 HTML、CSS、JS、图片、字体

HTTP/2 可以在一个连接里多路复用这些请求。

但是 HTTP/2 仍然跑在 TCP 上。如果 TCP 层某个包丢了,可能导致这个 TCP 连接里的多个流都被卡住。HTTP/3 标准介绍里也提到,HTTP/2 引入了二进制分帧和多路复用来改善延迟,但由于 TCP 的丢包恢复机制,一个丢包或乱序包会让所有活动事务发生停顿。(RFC 编辑器)


12.3 HTTP/3

HTTP/3 跑在 QUIC 上,而 QUIC 跑在 UDP 上。

结构大概是:

text 复制代码
HTTP/3
  ↓
QUIC
  ↓
UDP
  ↓
IP

HTTP/3 的优势:

text 复制代码
连接建立更快
多路复用更好
某个流丢包不容易卡住其他流
弱网、移动网络体验更好
内置 TLS 1.3 安全能力

HTTP/3 标准说明,它把 HTTP 语义映射到 QUIC 上,QUIC 提供协议协商、基于流的多路复用和流控;而且不同流相互独立,一个流阻塞或丢包不会阻止其他流继续前进。(RFC 编辑器)

不过对嵌入式 MCU 来说:

text 复制代码
HTTP/1.1 最常用、最简单
HTTPS + HTTP/1.1 很常见
HTTP/2 在部分 SDK/库里支持
HTTP/3/QUIC 对小 MCU 来说复杂度更高

13. HTTP/HTTPS 对带宽的影响

13.1 HTTP 头部有开销

比如你只想获取一个很小的 JSON:

json 复制代码
{"temp":25.6}

只有十几个字节。

但是 HTTP 请求头可能有几百字节:

http 复制代码
GET /weather HTTP/1.1
Host: api.xxx.com
User-Agent: ESP32
Accept: */*
Connection: close

响应头也可能几百字节:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 13
Date: ...
Server: ...

{"temp":25.6}

所以小数据频繁请求时,HTTP 头部开销比较明显。


13.2 HTTPS 有加密开销

HTTPS 比 HTTP 多:

text 复制代码
TLS 握手数据
证书数据
加解密计算
TLS 记录层开销

对大文件来说,这些开销占比不大。

对小 MCU 频繁短连接来说,TLS 握手和证书验证会比较明显。

所以嵌入式里不建议这样:

text 复制代码
每 1 秒建立一次 HTTPS 连接
请求一次
马上断开

更好的方式:

text 复制代码
连接复用
减少请求频率
批量上传数据
必要时使用 MQTT 长连接

14. HTTP 短连接和长连接

14.1 短连接

每次请求都重新建立 TCP:

text 复制代码
TCP连接
HTTP请求
HTTP响应
关闭TCP

TCP连接
HTTP请求
HTTP响应
关闭TCP

缺点:

text 复制代码
慢
浪费握手时间
浪费带宽
服务器压力大
HTTPS 下更明显

14.2 长连接 / Keep-Alive

一次 TCP 连接里发送多个 HTTP 请求:

text 复制代码
建立 TCP/TLS 连接
请求 1
响应 1
请求 2
响应 2
请求 3
响应 3
最后关闭连接

优点:

text 复制代码
减少 TCP 握手
减少 TLS 握手
降低延迟
提高吞吐

嵌入式建议:

text 复制代码
偶尔请求天气:短连接可以
频繁请求云端接口:尽量复用连接
OTA 下载:必须尽量稳定复用,支持断点续传更好

15. HTTP 下载 OTA 时的带宽问题

OTA 是 HTTP/HTTPS 的典型应用。

流程:

text 复制代码
ESP32 收到升级指令
  ↓
HTTPS 请求固件 URL
  ↓
服务器返回 app.bin
  ↓
ESP32 边下载边写入 OTA 分区
  ↓
下载完成,校验固件
  ↓
切换启动分区
  ↓
重启进入新固件

OTA 下载速度受这些影响:

text 复制代码
1. Wi-Fi 信号质量
2. 服务器下载速度
3. HTTPS 加密性能
4. Flash 写入速度
5. TCP 重传
6. 固件大小
7. 是否支持 Range 断点续传

比如固件 2 MB:

text 复制代码
2 MB ≈ 16 Mbit
实际吞吐 2 Mbps
理论下载时间 ≈ 8 秒

但实际可能 10~30 秒,因为还要考虑 HTTPS 握手、Flash 写入、网络波动、服务器响应等。


16. HTTP/HTTPS 和 MQTT 速度对比

这个你前面也问过 MQTT,顺便对比一下。

场景 HTTP/HTTPS MQTT
获取天气 很适合 没必要
下载 OTA 固件 很适合 不适合大文件
设备周期上报 能用,但频繁请求开销大 很适合
App 实时控制设备 可以轮询,但不优雅 很适合
一次性请求 API 很适合 不适合
长连接实时通信 WebSocket / HTTP/2 可做 MQTT 更自然
小数据高频通信 开销偏大 开销小

简单记:

text 复制代码
HTTP/HTTPS:适合"我问你答"、下载、上传、REST API
MQTT:适合"设备长期在线,云端/设备互相推消息"

17. 嵌入式开发怎么选?

获取天气

推荐:

text 复制代码
HTTPS GET

因为天气 API 一般就是 REST API。


设备上传日志

低频:

text 复制代码
HTTPS POST

高频:

text 复制代码
MQTT

OTA 升级

推荐:

text 复制代码
HTTPS GET 下载固件

不建议用 MQTT 传整个固件。


App 控制设备开关

推荐:

text 复制代码
MQTT

也可以用:

text 复制代码
HTTPS 轮询
WebSocket

但 MQTT 更适合 IoT。


AI 语音助手

可能组合是:

text 复制代码
HTTPS:请求配置、鉴权、OTA、下载资源
WebSocket:实时语音流、实时对话
MQTT:设备状态、控制命令、在线离线、事件上报

18. 总结

你可以这样记:

text 复制代码
HTTP 是应用层请求/响应协议。
HTTPS 是 HTTP + TLS 加密。
HTTP/1.1 简单,适合嵌入式新手和普通 API。
HTTP/2 支持二进制帧、多路复用,适合并发请求。
HTTP/3 基于 QUIC/UDP,弱网和移动网络表现更好,但 MCU 上复杂度更高。

对通信速度来说:

text 复制代码
小数据短连接:HTTPS 比 HTTP 慢,主要慢在 TLS 握手
连接复用后:HTTPS 和 HTTP 的差距会小很多
大文件下载:主要看实际带宽、丢包率、服务器、Flash写入速度
频繁小数据:HTTP/HTTPS 开销偏大,MQTT/WebSocket 更合适

嵌入式实际建议:

text 复制代码
天气/API请求:HTTPS GET
上传配置/日志:HTTPS POST
OTA升级:HTTPS GET + 断点续传
实时控制/状态上报:MQTT
实时语音/流式AI对话:WebSocket 或专用流式协议

1: https://datatracker.ietf.org/doc/html/rfc8446 "

复制代码
            RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3
        
    "



对,获取天气这个案例特别适合用来理解 HTTP / HTTPS

先给你一句话结论:

ESP32 获取天气,本质就是:ESP32 通过 Wi-Fi 连上互联网,然后向天气服务器发送一个 HTTP/HTTPS 请求,服务器返回一段 JSON 文本,ESP32 再解析 JSON,拿到温度、湿度、天气描述。

比如你用 OpenWeather,它的 Current Weather Data API 就是给指定城市或经纬度返回实时天气数据,返回格式可以是 JSON/XML/HTML,实际嵌入式里一般用 JSON。(OpenWeather)


1. 先看整个过程

假设你的 ESP32 要获取大阪天气:

text 复制代码
ESP32
  ↓ Wi-Fi 连接路由器
路由器
  ↓ 访问互联网
天气服务器 OpenWeather
  ↓ 返回天气 JSON
ESP32 解析 JSON
  ↓
LCD 显示:大阪 23℃ 多云

如果用 HTTP/HTTPS 请求,可以理解成:

text 复制代码
ESP32:你好,我要大阪的天气数据
服务器:好的,给你一段 JSON
ESP32:收到,我解析里面的温度、湿度、天气描述

2. 获取天气为什么适合用 HTTP?

因为获取天气属于:

text 复制代码
请求一次
返回一次
结束

比如:

text 复制代码
ESP32 请求:大阪现在天气?
服务器返回:23℃,多云,湿度 60%

这就是典型的 HTTP 请求-响应模型

所以获取天气一般不需要 WebSocket。

text 复制代码
获取天气:HTTP / HTTPS 就够
实时语音助手:WebSocket 更合适
OTA升级:HTTP / HTTPS 更合适

3. HTTP 是什么?

HTTP 全称是:

text 复制代码
HyperText Transfer Protocol
超文本传输协议

但是你别被"超文本"这个名字吓到。对嵌入式开发来说,你可以先这样理解:

HTTP 就是一套客户端和服务器之间"怎么说话"的规则。

比如 ESP32 想问天气服务器要数据,不能乱发:

text 复制代码
大阪天气给我

而是要按照 HTTP 格式发:

http 复制代码
GET /data/2.5/weather?q=Osaka&appid=你的API_KEY&units=metric&lang=zh_cn HTTP/1.1
Host: api.openweathermap.org
User-Agent: esp32
Connection: close

这就是一个 HTTP 请求报文。


4. HTTP 请求长什么样?

一个 HTTP 请求大概分 4 部分:

text 复制代码
请求行
请求头
空行
请求体

以获取天气为例:

http 复制代码
GET /data/2.5/weather?q=Osaka&appid=YOUR_API_KEY&units=metric&lang=zh_cn HTTP/1.1
Host: api.openweathermap.org
User-Agent: esp32
Connection: close

注意最后有一个空行。


4.1 请求行

这一行:

http 复制代码
GET /data/2.5/weather?q=Osaka&appid=YOUR_API_KEY&units=metric&lang=zh_cn HTTP/1.1

拆开看:

text 复制代码
GET                      请求方法
/data/2.5/weather?...    请求路径和参数
HTTP/1.1                 HTTP 协议版本

4.2 GET 是什么意思?

GET 表示:

我要从服务器获取数据。

获取天气、获取网页、获取图片,通常都可以用 GET。

比如:

text 复制代码
获取天气:GET
获取网页:GET
下载固件:GET

而上传数据通常用 POST

比如:

text 复制代码
上传录音:POST
提交表单:POST
上传传感器数据:POST 或 MQTT

4.3 URL 里的参数是什么意思?

这一段:

text 复制代码
/data/2.5/weather?q=Osaka&appid=YOUR_API_KEY&units=metric&lang=zh_cn

可以拆成:

text 复制代码
/data/2.5/weather       API 路径
?                       后面开始是参数
q=Osaka                 查询城市 Osaka
appid=YOUR_API_KEY      你的 API Key
units=metric            使用摄氏度
lang=zh_cn              返回中文天气描述

多个参数之间用 & 连接:

text 复制代码
q=Osaka
&
appid=YOUR_API_KEY
&
units=metric
&
lang=zh_cn

OpenWeather 的 Current Weather API 支持用城市名、城市 ID、经纬度、邮编等方式查询当前天气。(OpenWeather)


4.4 Host 请求头

这一行:

http 复制代码
Host: api.openweathermap.org

意思是:

我要访问的服务器域名是 api.openweathermap.org

因为一个服务器 IP 上可能部署多个网站,所以 HTTP/1.1 里 Host 很重要。


4.5 Connection 请求头

http 复制代码
Connection: close

意思是:

服务器返回数据后,可以关闭连接。

对 ESP32 新手来说,这个比较简单。

你可以先用短连接:

text 复制代码
连接服务器
发送请求
接收响应
关闭连接

不要一上来就搞长连接、Keep-Alive。


5. HTTP 响应长什么样?

服务器收到请求后,会返回类似这样的内容:

http 复制代码
HTTP/1.1 200 OK
Server: openresty
Content-Type: application/json; charset=utf-8
Content-Length: 512
Connection: close

{
  "weather": [
    {
      "main": "Clouds",
      "description": "多云"
    }
  ],
  "main": {
    "temp": 23.5,
    "humidity": 60
  },
  "name": "Osaka"
}

这就是 HTTP 响应。

它也可以拆成:

text 复制代码
状态行
响应头
空行
响应体

5.1 状态行

http 复制代码
HTTP/1.1 200 OK

意思是:

text 复制代码
HTTP/1.1    协议版本
200         状态码
OK          成功

常见状态码:

状态码 含义 嵌入式里怎么理解
200 成功 正常拿到天气
301/302 重定向 服务器让你换个地址访问
400 请求错误 参数写错
401 未授权 API Key 不对
403 禁止访问 没权限
404 找不到 API 路径错了
500 服务器错误 服务器内部问题

5.2 响应头

比如:

http 复制代码
Content-Type: application/json; charset=utf-8
Content-Length: 512

意思是:

text 复制代码
Content-Type: application/json
服务器返回的是 JSON 数据

Content-Length: 512
响应体长度是 512 字节

ESP32 解析天气时,真正关心的是响应体,也就是空行后面的 JSON。


5.3 响应体 Body

响应体就是这段:

json 复制代码
{
  "weather": [
    {
      "main": "Clouds",
      "description": "多云"
    }
  ],
  "main": {
    "temp": 23.5,
    "humidity": 60
  },
  "name": "Osaka"
}

ESP32 拿到它以后,用 cJSON 解析。

你关心的字段可能是:

text 复制代码
main.temp              温度
main.humidity          湿度
weather[0].description 天气描述
name                   城市名

6. HTTP 获取天气的完整链路

你在代码里可能只是调用:

c 复制代码
esp_http_client_perform(client);

但底层其实发生了很多事:

text 复制代码
1. ESP32 连接 Wi-Fi
2. 获得 IP 地址
3. DNS 解析 api.openweathermap.org
4. 得到服务器 IP
5. 建立 TCP 连接
6. 发送 HTTP GET 请求
7. 服务器返回 HTTP 响应
8. ESP32 读取响应数据
9. 从响应体中提取 JSON
10. cJSON 解析温度、湿度、天气描述
11. 关闭连接

ESP-IDF 的 esp_http_client 组件本身就是用于 HTTP/HTTPS 请求的客户端 API,官方文档也说明它支持 HTTP 和 HTTPS 请求。(Espressif Systems)


7. HTTP 在网络分层里处于哪一层?

可以这样看:

text 复制代码
应用层:HTTP / HTTPS
传输层:TCP
网络层:IP
链路层:Wi-Fi
物理层:2.4GHz 无线信号

获取天气时:

text 复制代码
HTTP 负责:我要什么资源、请求格式、响应格式
TCP 负责:可靠传输,丢包重传,保证顺序
IP 负责:从 ESP32 找到服务器
Wi-Fi 负责:无线收发数据

所以 HTTP 不是直接通过 Wi-Fi 发出去的,它下面还有 TCP/IP。


8. 用 socket 手写 HTTP 是什么感觉?

你之前看的 ESP-IDF plain POSIX sockets 示例,本质就是手动拼 HTTP 字符串。

比如:

c 复制代码
static const char *REQUEST =
    "GET /data/2.5/weather?q=Osaka&appid=YOUR_API_KEY&units=metric&lang=zh_cn HTTP/1.1\r\n"
    "Host: api.openweathermap.org\r\n"
    "User-Agent: esp32\r\n"
    "Connection: close\r\n"
    "\r\n";

然后通过 socket 发出去:

c 复制代码
send(sock, REQUEST, strlen(REQUEST), 0);

再接收服务器返回:

c 复制代码
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);

这个方式适合学习 HTTP 底层原理。

但是正式项目里,更建议用:

c 复制代码
esp_http_client

因为它帮你处理了很多细节,比如:

text 复制代码
URL 解析
HTTP header
重定向
HTTPS
证书
读取响应
事件回调

9. esp_http_client 获取天气大概怎么写?

简化版:

c 复制代码
#include "esp_http_client.h"
#include "esp_log.h"

static const char *TAG = "weather";

#define WEATHER_URL "http://api.openweathermap.org/data/2.5/weather?q=Osaka&appid=YOUR_API_KEY&units=metric&lang=zh_cn"

esp_err_t http_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id) {
    case HTTP_EVENT_ON_DATA:
        /*
         * 服务器返回的数据会从这里进来。
         * evt->data 是数据指针。
         * evt->data_len 是这次收到的数据长度。
         *
         * 注意:数据可能不是一次性收完整的。
         * 实际项目里要把数据追加到一个 buffer 里,
         * 收完之后再用 cJSON 解析。
         */
        ESP_LOGI(TAG, "Received data len=%d", evt->data_len);
        printf("%.*s", evt->data_len, (char *)evt->data);
        break;

    default:
        break;
    }

    return ESP_OK;
}

void get_weather_http(void)
{
    esp_http_client_config_t config = {
        .url = WEATHER_URL,
        .event_handler = http_event_handler,
    };

    esp_http_client_handle_t client = esp_http_client_init(&config);

    esp_err_t err = esp_http_client_perform(client);

    if (err == ESP_OK) {
        ESP_LOGI(TAG, "HTTP Status = %d",
                 esp_http_client_get_status_code(client));
    } else {
        ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err));
    }

    esp_http_client_cleanup(client);
}

这个是 HTTP 版本。


10. 那 HTTPS 是什么?

HTTPS 可以理解为:

HTTP + TLS 加密层

也就是:

text 复制代码
HTTP  = 明文通信
HTTPS = 加密通信的 HTTP

HTTP:

text 复制代码
ESP32 直接把请求明文发给服务器
别人抓包可能看到你的 API Key、请求内容、返回内容

HTTPS:

text 复制代码
ESP32 先和服务器建立 TLS 加密通道
然后 HTTP 请求在加密通道里面传输
别人抓包只能看到一堆加密数据

ESP-IDF 官方文档说明,esp_http_client 支持基于 mbedTLS 的 SSL/TLS 连接;当 URL 使用 https://,或者传输类型设置为 HTTP_TRANSPORT_OVER_SSL 时,就会走 HTTPS。(Espressif Systems)


11. HTTPS 和 HTTP 的区别

对比项 HTTP HTTPS
默认端口 80 443
是否加密 不加密 加密
是否校验证书 不校验 通常需要校验证书
抓包能否看到内容 能看到明文 只能看到密文
ESP32 实现难度 简单 稍微复杂
产品推荐 不推荐正式产品 推荐正式产品

12. HTTPS 多了什么流程?

HTTP 流程:

text 复制代码
ESP32
  ↓ TCP 连接
服务器
  ↓ HTTP 请求
服务器
  ↓ HTTP 响应
ESP32

HTTPS 流程:

text 复制代码
ESP32
  ↓ TCP 连接
服务器
  ↓ TLS 握手
服务器
  ↓ 证书校验
ESP32
  ↓ 建立加密通道
服务器
  ↓ 加密后的 HTTP 请求
服务器
  ↓ 加密后的 HTTP 响应
ESP32

所以 HTTPS 不是替代 HTTP,而是在 HTTP 外面套了一层安全壳。


13. TLS 握手用大白话讲

HTTPS 里面的 TLS 握手,大概可以理解成这样:

text 复制代码
ESP32:你好,我想安全通信
服务器:可以,这是我的证书
ESP32:我检查一下这个证书是不是真的
ESP32:证书可信,继续
双方协商出一把临时加密密钥
之后所有 HTTP 数据都用这把密钥加密传输

最关键的是服务器证书。

证书的作用类似:

text 复制代码
服务器拿出身份证
ESP32 检查这个身份证是不是可信机构签发的
如果可信,才继续通信

ESP-IDF 的 ESP-TLS 文档也说明,客户端可以通过验证服务器证书来确认服务器身份;如果没有选择服务器验证方式,TLS 建连时会失败。(Espressif Systems)


14. HTTPS 获取天气代码大概有什么不同?

HTTP:

c 复制代码
.url = "http://api.openweathermap.org/..."

HTTPS:

c 复制代码
.url = "https://api.openweathermap.org/..."

但 HTTPS 一般还要配置证书:

c 复制代码
extern const char server_cert_pem_start[] asm("_binary_server_cert_pem_start");
extern const char server_cert_pem_end[]   asm("_binary_server_cert_pem_end");

esp_http_client_config_t config = {
    .url = "https://api.openweathermap.org/data/2.5/weather?q=Osaka&appid=YOUR_API_KEY&units=metric&lang=zh_cn",
    .cert_pem = server_cert_pem_start,
    .event_handler = http_event_handler,
};

也就是说,HTTPS 比 HTTP 多了:

text 复制代码
1. URL 从 http:// 变成 https://
2. 端口从 80 变成 443
3. 底层多了 TLS 握手
4. 需要证书校验
5. RAM 消耗更高一点

15. 为什么 HTTPS 要证书?

因为加密不等于安全。

假设没有证书校验,攻击者可以假装自己是天气服务器:

text 复制代码
ESP32 → 假服务器
假服务器 → 返回假天气数据

证书校验就是为了防止:

text 复制代码
我以为我连的是 OpenWeather
实际上连到了别人伪造的服务器

所以正式产品里不要随便关闭证书校验。


16. HTTP 明文有什么问题?

HTTP 请求可能是这样的:

http 复制代码
GET /data/2.5/weather?q=Osaka&appid=abcd1234&units=metric&lang=zh_cn HTTP/1.1
Host: api.openweathermap.org

如果别人抓包,可能直接看到:

text 复制代码
城市名
API Key
请求路径
返回天气 JSON

对天气这种数据来说问题可能没那么大,但如果是:

text 复制代码
用户登录 token
设备密钥
OTA 固件地址
控制指令
AI 语音数据

那就比较危险。

所以正式产品建议用 HTTPS。


17. 获取天气到底用 HTTP 还是 HTTPS?

学习阶段:

text 复制代码
可以先用 HTTP
方便理解协议
方便用 Wireshark 抓包看明文
方便调试

正式项目:

text 复制代码
建议用 HTTPS
保护 API Key
防止请求被篡改
防止中间人攻击

尤其你以后如果做:

text 复制代码
AI 语音助手
OTA 升级
设备控制
用户账号
云端服务

这些都更应该用 HTTPS。


18. ESP32 获取天气时的数据流

以 HTTPS 为例:

text 复制代码
你的代码
  ↓
esp_http_client
  ↓
HTTP 请求
  ↓
TLS 加密
  ↓
TCP
  ↓
IP
  ↓
Wi-Fi
  ↓
路由器
  ↓
互联网
  ↓
OpenWeather 服务器

服务器返回时反过来:

text 复制代码
OpenWeather 服务器
  ↓
互联网
  ↓
路由器
  ↓
Wi-Fi
  ↓
IP
  ↓
TCP
  ↓
TLS 解密
  ↓
HTTP 响应
  ↓
esp_http_client
  ↓
你的回调函数
  ↓
cJSON 解析
  ↓
LCD 显示

19. JSON 解析又是什么?

服务器返回的不是 C 结构体,而是一段文本:

json 复制代码
{
  "main": {
    "temp": 23.5,
    "humidity": 60
  },
  "weather": [
    {
      "description": "多云"
    }
  ],
  "name": "Osaka"
}

ESP32 要把它解析出来:

text 复制代码
temp = 23.5
humidity = 60
description = 多云
name = Osaka

伪代码:

c 复制代码
cJSON *root = cJSON_Parse(json_string);

cJSON *main = cJSON_GetObjectItem(root, "main");
cJSON *temp = cJSON_GetObjectItem(main, "temp");
cJSON *humidity = cJSON_GetObjectItem(main, "humidity");

cJSON *weather = cJSON_GetObjectItem(root, "weather");
cJSON *weather0 = cJSON_GetArrayItem(weather, 0);
cJSON *desc = cJSON_GetObjectItem(weather0, "description");

printf("温度: %.1f\n", temp->valuedouble);
printf("湿度: %d\n", humidity->valueint);
printf("天气: %s\n", desc->valuestring);

cJSON_Delete(root);

20. 新手最容易踩的坑

坑 1:把 HTTP Header 当成 JSON 解析

服务器返回的是:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json

{"main":{"temp":23.5}}

真正 JSON 是空行后面的:

json 复制代码
{"main":{"temp":23.5}}

如果你用 socket 手写 HTTP,需要自己把响应头去掉。

但如果用 esp_http_client,通常 HTTP_EVENT_ON_DATA 里拿到的就是响应体数据,更方便。


坑 2:一次 recv 不一定收完整

很多新手以为:

c 复制代码
recv(sock, buffer, sizeof(buffer), 0);

一次就能收到完整 JSON。

不一定。

TCP 是流式协议,可能分几次到:

text 复制代码
第一次收到:{"main":
第二次收到:{"temp":23.
第三次收到:5}}

所以实际项目要把数据拼接起来,等接收完成后再解析 JSON。


坑 3:HTTPS 证书没配好

HTTPS 如果没配证书,可能连接失败。

你会看到类似:

text 复制代码
TLS handshake failed
certificate verify failed

学习阶段可以先用 HTTP 理解流程。

正式阶段再加 HTTPS 证书。


坑 4:API Key 写错

如果 API Key 错了,服务器可能返回:

json 复制代码
{
  "cod": 401,
  "message": "Invalid API key"
}

这时候 HTTP 本身可能连接成功,但业务结果失败。

所以你要区分:

text 复制代码
网络失败
HTTP 状态码失败
业务 JSON 返回失败

坑 5:城市名中文/空格没有 URL 编码

URL 里不能随便放特殊字符。

比如城市名如果有空格,要编码:

text 复制代码
New York → New%20York

中文城市名也可能需要 URL 编码。

新手阶段建议先用经纬度或者英文城市名。

比如:

text 复制代码
q=Osaka
q=Tokyo
q=Shanghai

21. 对你来说最推荐的学习路线

你可以按这个顺序学:

text 复制代码
第一步:用浏览器访问天气 API
第二步:用 curl 访问天气 API
第三步:ESP32 用 HTTP 获取天气
第四步:ESP32 解析 JSON
第五步:LCD 显示天气
第六步:把 HTTP 改成 HTTPS
第七步:处理证书、超时、错误码

比如电脑上先测试:

bash 复制代码
curl "https://api.openweathermap.org/data/2.5/weather?q=Osaka&appid=YOUR_API_KEY&units=metric&lang=zh_cn"

确认电脑能拿到 JSON 后,再移植到 ESP32。


22. 最后用一句话总结

HTTP 获取天气:

text 复制代码
ESP32 明文问服务器:大阪天气是多少?
服务器明文回答:23℃,多云

HTTPS 获取天气:

text 复制代码
ESP32 先确认服务器是真的
双方建立加密通道
ESP32 在加密通道里问:大阪天气是多少?
服务器在加密通道里回答:23℃,多云

你可以这样记:

text 复制代码
HTTP 解决"怎么请求数据"
HTTPS 解决"怎么安全地请求数据"
JSON 解决"服务器返回的数据怎么组织"
cJSON 解决"ESP32 怎么解析这些数据"

对于你的天气案例:

text 复制代码
学习调试:HTTP 可以
正式产品:HTTPS 更合适



好的,咱们用你做ESP32获取天气的例子,来拆解HTTP和HTTPS,让它对嵌入式新手也能理解。


1️⃣ HTTP 协议工作流程(明文通信)

HTTP 就是 超文本传输协议 (HyperText Transfer Protocol),简单理解就是"客户端和服务器之间用的聊天语言",它传输的是 明文,没有加密。

你用 ESP32 去 OpenWeatherMap 获取天气时,流程大概是这样:

步骤:

  1. 建立 TCP 连接

    • ESP32(客户端)先找到服务器 IP,比如 api.openweathermap.org,然后在 80 端口(HTTP 默认端口)建立 TCP 连接。
    • 这里就像你先打电话给服务器,确认能通话。
  2. 发送请求报文

    • ESP32 会发一条 HTTP GET 请求:

      复制代码
      GET /data/2.5/weather?q=Osaka&appid=你的APIKey HTTP/1.1
      Host: api.openweathermap.org
    • 就像你对服务器说:"请把大阪的天气给我"。这是明文的,任何抓包的人都能看。

  3. 服务器响应

    • 服务器收到请求后,生成响应报文:

      复制代码
      HTTP/1.1 200 OK
      Content-Type: application/json
      ...
      {"weather":[...],"main":{"temp":22.3},...}
    • 数据直接返回 ESP32。

  4. ESP32 解析数据

    • ESP32 收到 JSON 数据,解析温度、湿度等。
  5. 关闭连接

    • HTTP/1.1 默认可以保持长连接,但也可以关闭 TCP 连接,完成一次请求。

⚠️ 特点

  • 明文传输 → 易被抓包看到。
  • 简单,嵌入式实现容易。

2️⃣ HTTPS 协议工作流程(加密通信)

HTTPS = HTTP + SSL/TLS(安全套接层),可以理解成在 HTTP 外面套了一个加密"外壳"。

ESP32 在和服务器交流时,不是直接发明文,而是先"握手加密",然后再通信。

步骤:

  1. 建立 TCP 连接(端口443)

    • 和 HTTP 类似,但默认端口是 443
    • ESP32先和服务器打电话。
  2. TLS 握手(加密协商)

    • 这一步是HTTPS的核心:

      1. ESP32 -> 服务器:你好,我想加密通信,支持这些加密算法。
      2. 服务器 -> ESP32:好的,我们用这个算法,并给你一个证书(里面有公钥)。
      3. ESP32 验证证书是否合法(是否受信任 CA 签名)。
      4. ESP32 和服务器生成对称加密密钥(用公钥交换密钥)。
    • 握手完成后,双方都有同一个密钥,可以加密解密。

  3. 加密 HTTP 通信

    • ESP32 现在用这个对称密钥加密 GET 请求:

      复制代码
      GET /data/2.5/weather?q=Osaka&appid=你的APIKey HTTP/1.1
      Host: api.openweathermap.org
    • 传输的是密文,别人抓包也看不懂。

  4. 加密服务器响应

    • 服务器用同样密钥加密数据发回 ESP32,ESP32 解密后得到 JSON 数据。
  5. 关闭连接

    • 断开 TCP 连接,同时销毁密钥。

⚠️ 特点

  • 数据被加密 → 更安全。
  • 初次握手复杂 → 占用更多内存和时间,嵌入式需要注意 RAM/Flash。

3️⃣ 嵌入式开发注意点

项目 HTTP HTTPS
默认端口 80 443
安全性 高(加密 + 证书)
协议复杂度 简单 TLS握手复杂,内存消耗大
实现难度 高(需要 TLS 库,如 mbedTLS, wolfSSL)
抓包可见

💡 对于你的 ESP32:

  • 如果只是测试,HTTP 足够简单。
  • 真正发布产品,需要 HTTPS,否则 API Key 等敏感信息可能泄露。

如果你愿意,我可以帮你画一个 ESP32 获取天气的 HTTP 和 HTTPS 流程图,把握手、请求、响应的每一步画出来,直观又易懂。

你希望我画吗?

相关推荐
Chengbei116 小时前
面向红队的 AI 赋能全场景流量分析仪 网页 / APP / 终端 / IoT 全域 HTTPS 抓包解密利器
人工智能·物联网·网络协议·web安全·网络安全·https·系统安全
Hello_Embed6 小时前
【无标题】
网络·笔记·网络协议·tcp/ip·嵌入式
路溪非溪6 小时前
详解下DNS协议
网络·网络协议·tcp/ip·智能路由器
用户815577828217 小时前
连上WiFi 却打不开网页?一套常用命令帮你快速定位问题
网络协议
仍然.7 小时前
网络编程(一)---传输层协议和UDP数据报套接字编程
网络·网络协议·udp
上海云盾-小余8 小时前
动态 IP 隐匿技术:手游服务器规避端口扫描与溯源攻击实战
服务器·网络协议·tcp/ip
时空自由民.8 小时前
HTTP协议帧格式
网络·网络协议·http
雨浓YN9 小时前
GKMLT通讯工具箱(WPF MVVM) - 02-Modbus RTU 与 TCP 报文格式、原理与CRC校验
网络·网络协议·tcp/ip
雨浓YN9 小时前
GKMLT通讯工具箱(WPF MVVM) - 01-网口/串口通讯与 ModBus RTU/TCP
网络·网络协议·tcp/ip