用 Python Flask 搭建后端服务
← → 键切换 · 点击底部导航跳转
Python 最简单 Web 框架
3 个 API 接口,返回 JSON
?tag=坚持 按主题筛选
写 HTML 调用自己的后端
Flask 后端
3 个 API 接口
前端测试页面
调用后端的 API
先写后端,再写前端测试。两个文件都放在 lesson-03-backend/ 目录下
Web 框架,处理 HTTP 请求和路由
允许前端跨域访问(后面解释)
注意 在终端里运行,确保看到 "Successfully installed"
| 1-3 | """...""" | 文档字符串,说明这个文件的作用 |
| 5 | from flask import Flask, jsonify, request | ⚠️ 从 Flask 导入3样东西: Flask = 框架本身 jsonify = 把字典转成 JSON 返回 request = 拿到浏览器发送的请求数据 |
| 6 | from flask_cors import CORS | ⚠️ 导入跨域支持 不同端口号之间的通信需要它 |
| 7 | import random | Python 内置的随机库 random.choice() 随机选一条金句 |
创建 Flask 应用
__name__ 是 Python 的特殊变量
= 告诉 Flask 当前文件的名字
Flask 用它来找到资源路径
CORS = 跨域资源共享
前端的地址是 localhost 后打开 HTML
后端的地址是 localhost:5000
不同端口 = 不同"域"
CORS 允许它们互相通信
| 13-26 | QUOTES = [ ... ] | ⚠️ 一个大写的变量名 = Python 约定 全大写表示"这个数据是常量,不要改" |
| 每条数据:{ "quote", "author", "tag" } | ⚠️ 比之前多了一个 tag 字段! 用来按主题筛选(坚持/学习/创新/时间/人生) |
坚持4条 · 学习3条 · 创新2条 · 时间1条 · 人生2条
上节课的 API 只能随机
这节课我们可以按主题筛选
这和按 Arduino 传感器类型筛选一个道理
| 29 | @app.route('/') | ⚠️ 装饰器 = 告诉 Flask:当用户访问 "/" 这个路径时 执行下面这个函数 |
| 30 | def home(): | 函数名可以随便起,但要有意义 |
| 31 | return "..." | 返回字符串 → 浏览器直接显示这段文字 里面含 <a> 链接,点它跳到 /api/quote |
@app.route('/') = "当用户访问 http://localhost:5000/"
@app.route('/api/quote') = "当用户访问 http://localhost:5000/api/quote"
类似 Arduino 的中断:
"当引脚 2 收到信号时 → 执行这个函数"
| 37 | request.args.get('tag', '') | ⚠️ 从 URL 获取 ?tag=xxx 参数 第二个参数 '' 是默认值(没传就空字符串) |
| 41 | [q for q in QUOTES if q['tag'] == tag] | ⚠️ 列表推导式 从 QUOTES 中筛选出 tag 匹配的条目 |
| 43 | return jsonify(...), 404 | 返回错误信息 + HTTP 状态码 404(没找到) |
| 44 | return jsonify(random.choice(filtered)) | 从筛选结果中随机选一条返回 |
| 47 | return jsonify(random.choice(QUOTES)) | 没有 tag 参数 → 从全部中随机选 |
[q = 要放进新列表的东西
for q in QUOTES = 循环每一条
if q['tag'] == tag = 只选 tag 匹配的
如果 tag="坚持"
filtered = [
{荀子, 坚持}, {老子, 坚持}, {周易, 坚持}]
共3条
| 53 | jsonify({"quotes": QUOTES, "total": len(QUOTES)}) | 返回全部金句 + 总条数 |
| 59 | set(q['tag'] for q in QUOTES) | set = 集合,自动去重 5个标签 → {"坚持", "学习", "创新", "时间", "人生"} |
| 60 | sorted(tags) | 按字母排序 → 前端下拉框按顺序显示 |
接口1 = 获取单条金句(主要功能)
接口2 = 获取全部数据(浏览/调试)
接口3 = 获取标签列表(前端下拉框用)
| 63 | if __name__ == '__main__': | ⚠️ Python 特殊写法 只有直接运行这个文件时才会执行 如果被别的文件导入,不会运行 |
| 64-71 | print(...) | 打印启动信息,告诉学生有哪些地址可以访问 |
| 73 | app.run(host='0.0.0.0', port=5000, debug=True) | ⚠️ 启动服务器 host='0.0.0.0' = 允许局域网访问 port=5000 = 端口号 debug=True = 修改代码后自动重启 |
ModuleNotFoundError: No module named 'flask'
→ 没装依赖,运行 pip install flask flask-cors
Address already in use
→ 端口被占用了,关掉其他 Python 进程
打开浏览器,在地址栏输入:
→ 显示文字
→ 随机一条 JSON
→ 筛选"坚持"的 JSON
→ 全部标签
简单的前端,调用自己的后端 API
让用户选择主题
JS 读 select.value 拿到选中的值
之前调用公网 API
现在调用 localhost:5000 自己的 API
代码几乎一样!
| 73-75 | `http://localhost:5000/...${tag}` | ⚠️ 模板字符串(反引号) ${tag} 会被替换成选中的主题值 |
| 74 | ?tag=${tag} | 拼出 URL:?tag=坚持 |
| 88 | data.quote | 注意字段名变了! 第2课用 data.content(公网API) 这节课用 data.quote(自己API) |
• 使用 反引号 ` 而不是普通引号 ' 或 "
• 用 ${变量名} 插入变量
• 可以换行(不用写 + 号)
例子:
tag = "坚持"
\`...?tag=${tag}\` → "...?tag=坚持"
获取5个元素:quoteText, quoteAuthor, fetchBtn, tagSelect, errorMsg
async function fetchQuote()
→ 拿 tag → 构造 URL → fetch → 展示
fetchBtn.addEventListener('click', fetchQuote) — 和之前一样的绑定方式
相同点:
async/await · fetch · try/catch · finally · addEventListener
不同点:
URL 从公网 → localhost
新增 select 下拉框
字段名 data.quote vs data.content
先写后端,再写前端
pip install flask flask-cors
导入 → 初始化 → 金句数据 → 3个路由 → 启动
python app.py → 查看终端输出
访问 /api/quote → 看到 JSON 数据
前端页面 → select + fetch → 调用后端
选主题 → 获取金句 → 成功!
浏览器报错:net::ERR_CONNECTION_REFUSED
→ 先确认 python app.py 在运行
data.quote 写成 data.content
→ 看调试面板里字段叫什么
localhost:5000 写成 localhost
→ Flask 默认 5000 端口
Access-Control-Allow-Origin
→ 检查 app.py 里有 CORS(app)
第2课:浏览器 → 公网 API (api.quotable.io) → 展示
第3课:浏览器 → 自己的 API (localhost:5000) → 展示
流程完全一样!只是 API 地址从公网换成了自己的电脑
| 路径 | 方法 | 参数 | 返回 |
|---|---|---|---|
| /api/quote | GET | ?tag=可选 | 随机一条金句 |
| /api/quotes | GET | 无 | 全部12条 |
| /api/tags | GET | 无 | 5个标签列表 |
一个 API = 一个功能
把不同功能拆成不同的 URL 路径
/api/quote = 拿金句
/api/quotes = 拿所有金句
/api/tags = 拿标签
以后加功能:加新的路由就行,不影响旧的
在 QUOTES 列表里加条目,加新 tag
/api/stats → 返回各主题的金句数量
不只用 GET,试试 POST 传数据
把 test.html 改成漂亮卡片
✅ Flask 创建 Web 应用
✅ @app.route() 路由装饰器
✅ jsonify() 返回 JSON
✅ request.args.get() 接收 URL 参数
✅ 列表推导式 筛选数据
✅ if __name__ == '__main__' 启动入口
✅ CORS() 跨域支持
✅ 前端模板字符串 \`...${}\`
✅ 3 个 API 接口的设计
🎊 你有自己的 API 了!朋友们可以访问你的电脑 ✨
下节课预告 🤖 接入 AI,让金句实时生成!