可以,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 获取天气时,流程大概是这样:
步骤:
-
建立 TCP 连接
- ESP32(客户端)先找到服务器 IP,比如
api.openweathermap.org,然后在 80 端口(HTTP 默认端口)建立 TCP 连接。 - 这里就像你先打电话给服务器,确认能通话。
- ESP32(客户端)先找到服务器 IP,比如
-
发送请求报文
-
ESP32 会发一条 HTTP GET 请求:
GET /data/2.5/weather?q=Osaka&appid=你的APIKey HTTP/1.1 Host: api.openweathermap.org -
就像你对服务器说:"请把大阪的天气给我"。这是明文的,任何抓包的人都能看。
-
-
服务器响应
-
服务器收到请求后,生成响应报文:
HTTP/1.1 200 OK Content-Type: application/json ... {"weather":[...],"main":{"temp":22.3},...} -
数据直接返回 ESP32。
-
-
ESP32 解析数据
- ESP32 收到 JSON 数据,解析温度、湿度等。
-
关闭连接
- HTTP/1.1 默认可以保持长连接,但也可以关闭 TCP 连接,完成一次请求。
⚠️ 特点:
- 明文传输 → 易被抓包看到。
- 简单,嵌入式实现容易。
2️⃣ HTTPS 协议工作流程(加密通信)
HTTPS = HTTP + SSL/TLS(安全套接层),可以理解成在 HTTP 外面套了一个加密"外壳"。
ESP32 在和服务器交流时,不是直接发明文,而是先"握手加密",然后再通信。
步骤:
-
建立 TCP 连接(端口443)
- 和 HTTP 类似,但默认端口是 443。
- ESP32先和服务器打电话。
-
TLS 握手(加密协商)
-
这一步是HTTPS的核心:
- ESP32 -> 服务器:你好,我想加密通信,支持这些加密算法。
- 服务器 -> ESP32:好的,我们用这个算法,并给你一个证书(里面有公钥)。
- ESP32 验证证书是否合法(是否受信任 CA 签名)。
- ESP32 和服务器生成对称加密密钥(用公钥交换密钥)。
-
握手完成后,双方都有同一个密钥,可以加密解密。
-
-
加密 HTTP 通信
-
ESP32 现在用这个对称密钥加密 GET 请求:
GET /data/2.5/weather?q=Osaka&appid=你的APIKey HTTP/1.1 Host: api.openweathermap.org -
传输的是密文,别人抓包也看不懂。
-
-
加密服务器响应
- 服务器用同样密钥加密数据发回 ESP32,ESP32 解密后得到 JSON 数据。
-
关闭连接
- 断开 TCP 连接,同时销毁密钥。
⚠️ 特点:
- 数据被加密 → 更安全。
- 初次握手复杂 → 占用更多内存和时间,嵌入式需要注意 RAM/Flash。
3️⃣ 嵌入式开发注意点
| 项目 | HTTP | HTTPS |
|---|---|---|
| 默认端口 | 80 | 443 |
| 安全性 | 无 | 高(加密 + 证书) |
| 协议复杂度 | 简单 | TLS握手复杂,内存消耗大 |
| 实现难度 | 低 | 高(需要 TLS 库,如 mbedTLS, wolfSSL) |
| 抓包可见 | 是 | 否 |
💡 对于你的 ESP32:
- 如果只是测试,HTTP 足够简单。
- 真正发布产品,需要 HTTPS,否则 API Key 等敏感信息可能泄露。
如果你愿意,我可以帮你画一个 ESP32 获取天气的 HTTP 和 HTTPS 流程图,把握手、请求、响应的每一步画出来,直观又易懂。
你希望我画吗?