联网与通信
第 22 课:HTTP 请求——板子去访问网页
板子当客户端去访问外部服务器,看懂状态码和返回的那堆文本
我是吴老师。这节课跟上一节正好反过来。
上一节课,板子是服务器——它开着热点坐在那儿,等别人来访问它,你的手机是客人,上门敲门。这节课,板子变成客户端——它自己出门,去访问别人。 上一节它答话,这一节它问话。同一件事的两面,你两节都摸过了,这件事才算真的懂。
而且今天你问的是外面世界的东西。前面所有的实验,板子都只在你的桌子上自娱自乐——它读的是你房间里的光、你桌上的温度、你手边的距离。从这一课起,它读到的是真实世界的数据。
一、客户端和服务器,到底谁是谁
这两个词你肯定听过,但我得给你说准了,因为很多人学了好几年还是含含糊糊的。别从"谁厉害"去理解,从"谁主动"去理解。
| 谁主动 | 干什么 | 例子 | |
|---|---|---|---|
| 客户端 | 主动去问 | 发起请求,等答案 | 你的浏览器、你的板子 |
| 服务器 | 等着被问 | 收到请求,给答案 | 网站的后台、上一课的板子 |
服务器的特点不是"强大",是"一直开着、随时等着"。
你现在正在用的东西——浏览器——就是个客户端。你在地址栏敲一个网址回车,浏览器就替你去问了一趟,把答案拿回来画在屏幕上。你的板子今天要干的事,跟浏览器一模一样。 只不过浏览器会把答案"画"成漂亮的网页,而板子只会把答案原样打印出来——这个差别很重要,第五节专门讲。
二、一次 HTTP 请求长什么样
这个"你问我答"的过程有个正式名字叫 HTTP。别被这三个字母吓到,它就是"客户端和服务器之间对话的一套规矩"。 规矩很简单,一来一回:
① 客户端先开口,说清楚"我要什么"。这一句叫请求。② 服务器答一句,把结果送回来。这一句叫响应。
就这两步。 没有第三步,没有握手,没有寒暄。HTTP 是一场特别公事公办的对话。
注意这个顺序:永远是客户端先开口。 服务器不会主动找你说话,它只会坐在那儿等。这一点你记住,第 24 课 ESP-NOW 你会看到"主动推"和"等着被问"的区别。
三、GET 和 POST:一个去取,一个去寄
请求分两种,名字看着眼生,其实特别好懂。
我给你打个比方,你一下就能记住。GET = 去取快递。 你走到快递柜前面,报一个单号,柜子把东西给你——你是去"拿"东西的,报个号就行。POST = 寄一个包裹。 你抱着一个箱子去快递点,东西要跟着你一起送过去——你交出去的不只是"我来寄个东西"这句话,还有一个实实在在的包裹。
对应到代码里:
| GET | POST | |
|---|---|---|
| 干什么 | 我要拿点什么 | 我要提交点什么 |
| 参数放哪 | 拼在网址后面 | 装在"请求体"里 |
| 长什么样 | ?city=beijing&day=2 |
藏在请求里面,地址栏看不见 |
| 什么时候用 | 查天气、取数据、读状态 | 提交表单、上传数据、登录 |
最后一行那个区别有个很实际的后果:GET 的参数是露在外面的,所以绝对不能拿它传密码。 你想想,密码写在地址栏里,截图发出去、浏览器历史记录留着、路由器日志记着——全漏了。该用 POST 的时候用 GET,是一个真实存在的安全问题。现在你知道了。
拿不准用哪个的时候就这么判断:只是去问问、取点东西 → GET;要把东西交上去 → POST。
这节课我们只用 GET,因为它简单、看得见。等到第 23 课 MQTT、第 34 课联网天气站,你还会碰到它。
四、状态码:先看它,再看代码
服务器答话的时候,第一句不是内容,是一个三位数字,这个东西叫状态码。它是你排查时最值钱的一条线索。
| 状态码 | 意思 | 你该干什么 |
|---|---|---|
200 |
成功 | 你要的东西就在返回内容里 |
404 |
找不到 | 那边没有你请求的这个地址——多半是网址写错了 |
500 |
服务器自己出错了 | 不是你的事,等会儿再试 |
403 |
不让看 | 需要钥匙(API key),或者你的访问被拒了 |
429 |
你问得太频繁了 | 被限流了,等一会儿再试 |
这张表里,前三个你必须记住。 我要专门说一句 404 和 500 的区别,因为这两个混起来会浪费你一整晚:
404是"你找错门了"——地址不对,问题在你这边(或者对方把东西挪走了)500是"我家里出事了"——门找对了,是服务器自己倒了,跟你的代码一个字的关系都没有
记住这句话:看到不是 200,先看状态码,再怀疑自己的代码。 这就是第 5 课那句"先看现象,再猜原因"在联网里的样子——在硬件里,现象是灯不亮;在联网里,现象就是这个三位数。
五、返回内容不是网页,是一堆给程序看的文本
这一节要讲清一件事,它是很多人学了半年还没搞明白的一个坎。
你在浏览器里打开一个网页,看到的是排版好的标题、图片、按钮。但你的板子拿到的,是完全不一样的东西。
| 浏览器拿到的 | 板子拿到的 | |
|---|---|---|
| 内容 | 一堆文字(HTML) | 一堆文字(大多是 JSON) |
| 谁加工了 | 浏览器帮你"渲染"成了网页 | 没人加工,原样打印 |
关键在"渲染"这两个字。 服务器发给浏览器的,其实是一段描述"这个页面该长什么样"的文字,浏览器拿到之后照着这段文字把页面画出来,这段文字就叫 HTML。这就是上一课埋的那颗种子:板子写说明书,浏览器照着搭。
而板子去请求数据接口的时候,对方回的是更纯粹的东西——只有数据,没有任何"怎么画"的说明。 那个格式叫 JSON,你看一眼就懂了:
{
"latitude": 39.9,
"current": {
"time": "2026-09-17T10:00",
"temperature_2m": 24.3
}
}看明白了吗?就这么几条规矩:{} 是"一包东西","名字": 值 是一条(名字要用双引号括起来),[] 是"一串",{} 里面还能再套 {}。它就是一串有格式的文本,没有加密,没有玄机,你肉眼就能读懂。
那怎么把
24.3抠出来? 第 7 课你学过"先打印,再判断"——这节课你只要把它整个打出来看就行。 真正要从中取值的时候(第 34 课联网天气站),我们会用一个叫ArduinoJson的库。现在不用急,先学会"看到它、认识它"。
六、动手:让板子取一段真实的数据回来
第一步,先把 WiFi 连上——这段不用新代码,第 20 课原样搬过来。连不上的话,回去翻第 20 课第五节的排查顺序。
第二步,发一个 GET 请求:
#include <WiFi.h>
#include <HTTPClient.h>
const char* WIFI_NAME = "你家 WiFi 名字";
const char* WIFI_PASS = "你家 WiFi 密码";
void setup() {
Serial.begin(115200);
delay(1500);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_NAME, WIFI_PASS);
Serial.print("正在连 WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("连上了,IP:");
Serial.println(WiFi.localIP());
}
void loop() {
HTTPClient http;
String url = "http://api.open-meteo.com/v1/forecast"
"?latitude=39.9&longitude=116.4¤t=temperature_2m";
Serial.println("请求地址:" + url);
http.begin(url);
int code = http.GET(); // 发出去,拿回一个状态码
Serial.print("状态码:");
Serial.println(code);
if (code == 200) {
String body = http.getString(); // 把返回的文本整个拿回来
Serial.println("返回内容:");
Serial.println(body);
} else {
Serial.println("没成功——先看状态码,再怀疑代码");
}
http.end(); // 用完要收尾,不然连接会越攒越多
delay(10000); // 别刷太快,免费接口有限制
}烧进去,打开串口监视器。你会看到屏幕上滚出一大堆东西,长得跟上面那段 JSON 差不多。这就是从几百公里外的一台服务器上传回来的、此时此刻的真实数据。
关于那个网址,我说三件事。
① 它是公网上的一个免费天气接口,不需要注册、不需要 API key。
② 它随时可能挂。 免费接口就是这样——维护它的人不欠你什么,哪天关了就是关了。这不是你的代码错,第八节专门讲。
③ 如果你的库版本编译时报错,说
begin()的参数不对,改成这两行的写法:C++ WiFiClient client; http.begin(client, url);报错原文是最好的线索,把它复制给 AI,比描述现象有用得多。
第三步,故意制造一个 404——这一步别跳过,它比前面那步还值钱。 把网址里的 /v1/forecast 改成 /v1/forecats(故意拼错),再跑一遍,看状态码打印出什么。是 404。现在你亲眼见过它了——以后调试时再看到这个数,你不会慌,你知道那是"地址找错了",而不是"我的板子坏了"。
七、失败的时候,按这个顺序查
这一课的排查又跟前面两课不一样。 第 20 课查的是"能不能进网",第 21 课查的是"别人能不能连上我",这一课查的是"我出去这一趟,卡在哪一段"。
第 1 步:WiFi 连上了吗
先看串口有没有打印出 IP 地址。 没有 → 别查了,回第 20 课。 IP 都没拿到,后面全是白费劲。这一步看着废话,但它排在最前面是有道理的:很多人会跳过它,直接怀疑接口。
第 2 步:拿电脑浏览器访问同一个网址
这一步能省掉你一半的排查时间,我说真的。 把代码里那个 url 原封不动复制出来,粘到电脑浏览器的地址栏里回车,然后看:
| 电脑上打不开 | 电脑上能打开 |
|---|---|
| 问题不在你的板子(对方服务器挂了 / 你家网不通) | 问题在板子这边 |
| 你的代码一个字都不用改 | 回第 1 步查板子,或者往下看状态码 |
这一步的意义在于:它把"外面的世界"和"你的代码"一刀切开了。不然你会陷入最痛苦的一种调试——改半天代码,其实是对方服务器倒了。
第 3 步:状态码是多少
回到那张表看一眼:404 → 地址错了,仔细对一遍网址,一个字符一个字符对;500 → 对方的锅,等十分钟再试;429 → 你请求太频繁了,把 delay 调大一点;403 → 这个接口要 API key,换一个;负数(比如 -1) → 根本没连上,回第 1 步查 WiFi。
第 4 步:把返回内容的前面一段打出来
有些接口失败的时候不是给你一个错误码,而是回一段说明文字。你不知道它说了什么,就只能瞎猜。 把返回内容整个打印出来,往往答案就在里面。
第 5 步:是不是这个接口需要 https
有些网站只支持 https://,你用 http:// 去请求它会直接失败。 这种情况下得换一套写法(WiFiClientSecure),比现在这个麻烦一些。判断方法:把网址改成 https:// 粘到浏览器里试试——如果 http 打不开、https 能打开,那就是这个问题。
我在第一节就说过:联网故障看不见摸不着。 但现在你手上有一套五步顺序了,每一步都在回答一个具体的问题:网通了吗?外面活着吗?对方说什么了?它回了啥?是不是协议不对?这比"我再改改代码试试"强一百倍。
八、必须提醒你的一件事:免费接口不欠你什么
这一段我要专门说,因为它是很多人放弃联网课的地方。
公网上的免费接口有这么几个特点,你提前知道了,就不会怀疑自己:
- 随时可能挂。 今天好好的,明天就 500 了,后天可能域名都没了。
- 可能有限流。 一分钟请求超过多少次,它就把你拒了(
429)。 - 可能变规矩。 昨天不用注册,今天要 key 了;昨天返回这个字段,今天改名了。
- 可能很慢。 有时候要等三五秒才回,不是你的板子卡了。
最要命的是——这四种情况,从你的板子上看,现象都差不多:请求失败了。 所以你一定要养成刚才第 2 步那个习惯:先拿电脑浏览器试一遍。电脑上也不行,那就真不是你的问题。 换个接口,或者过两天再试,都行。别对着正确的代码改一整晚。
说句实在的:你现在体会到的是真实开发者的日常。真实项目里,大部分时间不是花在"写代码",而是花在"搞清楚为什么这次又不行了"。写得快不算本事,查得准才算。
自测
答案与解析
最核心的区别不是"读还是写",而是参数放在哪儿。GET 的参数拼在网址上,地址栏里看得见;POST 的参数装在请求体里,外面看不见。由此带来一个实际后果:GET 不能用来传密码——它会留在浏览器历史、路由器日志里。拿不准的时候记那句话:去取用 GET,去寄用 POST。
404。下面哪个判断是对的?答案与解析
404 是"你找错门了",500 才是"我家里出事了"。 这两个一定要分清:404 通常要回头改你自己的东西(网址拼错了、路径挪了),500 是对方的锅,你改什么都没用。如果看到的是负数(比如 -1),那才是根本没连上,要回第 20 课查 WiFi。
答案与解析
这一步的作用是"一刀切开外面和里面":电脑也打不开 → 问题在外面(服务器挂了 / 你家网不通),你的代码一个字都不用改;电脑能打开 → 问题在板子这边,回去查 WiFi 和状态码。跳过这一步,你就会陷入最痛苦的调试——改半天代码,其实是对方服务器倒了。
答题要点
答题要点应该包含:服务器发出去的东西其实是同一类东西——一堆文本。 区别在于谁加工了它:浏览器的职责之一就是渲染,它拿到 HTML 之后,照着那堆文字把标题、图片、按钮"画"出来给你看;板子没有渲染这一步,它拿到什么就原样打印什么。另外,板子去请求的往往是数据接口,对方回的干脆就是只有数据、没有排版说明的 JSON。关键词是"渲染"——说清楚这两个字,就说明理解了浏览器和板子的分工。
拓展HTTPS 和 HTTP 差在哪?为什么板子访问 https 网站要额外折腾?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"WiFiClientSecure ESP32 证书指纹"、"TLS 握手 是什么"。想一想:如果板子没法确认"对面真的是那台服务器",会发生什么?
拓展返回的那堆 JSON,怎么才能只把温度抠出来?
这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。
提示:搜"ArduinoJson 解析 示例"、"JSON 嵌套 取值"。想一想:如果不用库,靠自己在一大串文字里查找字符,会遇到什么麻烦?
本节你要动手做的事
- [ ] 先连上 WiFi:把第 20 课的代码搬过来,确认串口打印出 IP
- [ ] 发出第一个 GET 请求:跑通那段代码,看状态码是不是
200 - [ ] 把返回内容整段读完:不要只看开头就滑走,找到里面那个温度值
- [ ] 故意制造
404:把网址路径拼错,看状态码变成几。记住这个数 - [ ] 用电脑浏览器访问同一个网址:确认它活着,也看看电脑上"渲染"出来的样子,和板子拿到的文本差多少
- [ ] 把返回内容前 100 个字符抄进笔记:以后接口变了,你能对比出来哪里变了
- [ ] 把
delay从 10000 改成 1000 试试:看看多久之后会开始出问题
这一节课,你的板子第一次跟外面的世界发生了关系。
前面十九节课,它读的全是你桌上的东西:你房间的光、你手边的距离、你说话的声音。今天它读到的是几百公里外、此时此刻真实的天气。而你只写了不到三十行代码。
我觉得这件事值得你停下来想一想。但原理其实很朴素——报名字、拿地址、把请求送出去、把答案接回来。你把这几层都看穿了,你就不只是在"抄代码"。
下一节,我们上第 23 课:MQTT 与巴法云。今天你是主动去问——你问了才有答案。下一节我们要学一种"不用问,消息自己会来"的方式:手机发一条消息,板子那边立刻就动。
这才是"远程控制"真正的样子。