13-2 的 Flask 只开了一个开关,本节把它升级成能同时伺候【动作指令】和【视频流】的控制台——关键是 threaded 模式,以及绕开 Flask 3 已经删掉的老写法。
13-2 用 Flask + gpiozero 做了一次浏览器点灯,那是 Flask 的最小形态;本节回到同一个框架,补上它做【遥控台】必需的两块能力:多个路由协同与并发处理长响应。15-4 会直接把本节的成果拼上 15-2 的电机和 10 章的相机。
一、为什么还要回头讲 Flask
13-2 那次是【一个页面、一个按钮、一次请求】——请求发出去、GPIO 切一下、响应立刻返回,几十毫秒的事。遥控车完全不同,它有两个特殊要求:
- 动作要分得细:前进、后退、左转、右转、停车、调速,每个都要一个独立入口——这需要多个路由;
- 有一条请求永远不返回:MJPEG 视频流是【服务器不停地往浏览器推帧】,一个响应持续几分钟甚至几小时——这条请求会独占一个连接线程。
第 2 条是本节真正的技术核心。
二、路由:给每个动作开一个门
Flask 用装饰器把 URL 和函数绑在一起:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.get("/") # 首页:返回控制面板 HTML
def index():
return PANEL_HTML
@app.post("/move/<direction>") # 动作路由:/move/forward 等
def move(direction):
speed = float(request.args.get("speed", 0.6)) # 从查询串取速度
# 这里调用 15-2 的电机对象
return jsonify({"action": direction, "speed": speed})
三种常用参数位置,别混:
| 位置 | 写法 | 典型用途 |
|---|---|---|
| 路径参数 | /move/<direction> |
动作名(forward/stop) |
| 查询串 | /move/forward?speed=0.8 |
可选的数值(速度) |
| 表单/JSON 体 | request.get_json() |
复杂结构(本章用不上) |
HTTP 方法也要讲规矩:查询用 GET,改变硬件状态的动作用 POST——这样浏览器预取、刷新页面时不会误发动作(否则刷新一下车就冲出去)。
三、threaded=True:本节的生命线
Flask 自带的开发服务器默认是单线程的:一个请求处理完才接下一个。把视频流接上去,灾难立刻发生——视频流那条响应【永不结束】,服务器就永远在处理它,所有动作请求全排队,你的车就会【按了按钮半天没反应】,甚至按了完全不动。
解法一行:
app.run(host="0.0.0.0", port=5000, threaded=True)
threaded=True 让每个请求各占一个线程:视频流自己占一条,动作请求随时能挤进来。这是遥控车能不能开起来的分水岭——不开这个参数,代码全对、车就是不动。
补充两个参数的含义:
host="0.0.0.0":监听所有网卡——只有这样才能从手机访问;写127.0.0.1就只有树莓派自己能访问(13-2 已踩过);port=5000:Flask 默认端口,局域网内不冲突就行。
四、老教程里已失效的写法(Flask 3 换代)
Flask 现在的主版本是 3.x(3.1.3 于 2026 年 2 月发布)。3.0 一次性删掉了一批老教程里的常客,照抄必报错:
| 老写法 | 现在的替代 | 说明 |
|---|---|---|
@app.before_first_request |
应用工厂里初始化,或 with app.app_context(): |
3.0 已移除,报错说没有这个属性 |
FLASK_ENV=development |
FLASK_DEBUG=1 或 flask run --debug |
环境变量已删,设了也不会开调试 |
app.config["JSON_AS_ASCII"] 等 |
app.json.ensure_ascii = False |
JSON 配置键全家已删 |
send_file(..., attachment_filename=) |
download_name= |
参数 2.0 改名、3.0 收尾,旧名直接 TypeError |
另一个必须知道的事实:app.run() 启动的是 Werkzeug 开发服务器,官方明确说它不能用于生产。本课所有场景都在自家局域网内调试,用它没问题;但绝不要把它暴露到公网——没有并发防护、没有安全加固,等于把车和树莓派一起送人。
五、安全提醒:局域网内也别忘了关门
Flask 服务默认没有任何认证——同一个 WiFi 下任何人打开 http://<树莓派IP>:5000 都能开你的车。三条最低限度的防护:
- 改端口(比如 8000):躲开扫描器的默认目标;
- 加一个简单口令:路由里查
request.args.get("key")是否匹配; - 只在家里 WiFi 用,不要做端口转发映射到公网。
六、动手 Demo:三路由控制台(不接电机也能跑)
先不接电机,只验证路由与并发——路由通了,接上电机就是 15-4:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.get("/")
def index():
return "<h1>控制台</h1><p>POST /move/forward?speed=0.6 试试</p>"
@app.post("/move/<direction>")
def move(direction):
speed = float(request.args.get("speed", 0.6))
print("收到动作:", direction, "速度:", speed) # 用日志代替真实电机
return jsonify({"action": direction, "speed": speed})
@app.get("/status")
def status():
return jsonify({"ok": True})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, threaded=True)
在树莓派上跑起来(python3 app.py),然后开两个终端分别测:
# 终端 A:模拟视频流——一条永不结束的响应
curl -N http://127.0.0.1:5000/status
# 终端 B:动作请求
curl -X POST "http://127.0.0.1:5000/move/forward?speed=0.6"
curl -X POST "http://127.0.0.1:5000/move/stop"
看到什么算成功:终端 B 的动作请求立刻返回:
{"action": "forward", "speed": 0.6}
同时树莓派的控制台打印【收到动作: forward 速度: 0.6】。
读结果:把 threaded=True 改成 False 再重跑一遍上面的测试——动作请求会卡住直到终端 A 断开为止。亲眼看一次这个对比,胜过记十遍结论。
30 秒实验
在树莓派上开三个终端,同时(用 & 或三个窗口)各发一次请求:
for i in 1 2 3; do curl -s -X POST "http://127.0.0.1:5000/move/forward?speed=0.$i" & done; wait
三条请求会几乎同时返回(顺序可能交错)。这证明线程模式下请求是并发处理的——这也意味着:两个用户同时按下【前进】和【后退】,服务器会先后执行两条指令,最终状态以后到的为准。多人同时遥控同一台车,逻辑上必然打架,这也是本章不做多用户支持的原因。
七、常见误区
- 路由写好了,车就是不动,怀疑接错线 —— 先查
threaded=True。视频流占着唯一线程时,动作请求根本得不到执行,接线再对也没用。 - 用 GET 请求做动作 —— 浏览器的预取、后退、刷新都可能重发 GET;动作类接口一律 POST,避免【刷新页面车就跑】。
- 老教程里
before_first_request抄来就能用 —— Flask 3.0 已删除该装饰器;初始化代码写进应用工厂或with app.app_context():块。 - 反正家里局域网,不用管安全 —— 同一 WiFi 下任何设备都能访问,别把服务暴露到公网;加个口令、换个端口是最低成本的自保。
自测三问(点开对答案)
1. `threaded=True` 为什么是遥控车项目的必需项? 视频流是永不结束的响应,会独占线程;单线程模式下所有动作请求都会被它堵死,车无法响应。 2. 动作接口为什么用 POST 而不是 GET? GET 会被浏览器预取、刷新、历史回退触发重发;动作用 POST 可避免【刷新一下车就冲出去】这类事故。 3. Flask 3 里 `FLASK_ENV=development` 还有用吗? 没有,该环境变量已在 3.0 移除;改用 `FLASK_DEBUG=1` 或 `flask --app app run --debug`。- ☐ 下一节(15-4 打造树莓派 WiFi 遥控视频车)
相关笔记
- Web 界面的 GPIO 控制 —— Flask 的最小形态,本节的起点
- 架设 Web 服务器 —— Web 服务端知识的第一站
- 打造树莓派 WiFi 遥控视频车 —— 本节成果的落地处
- 🍓 树莓派 · 索引 —— 全课路线图