知识点思维导图
25 个知识节点
参考资料
Python(13) - Web 后端概览
读完后,你应能完成以下任务:
- 绘制“Python(13) - Web 后端概览 / 先建直觉:node 把服务器和框架揉成了一坨”的关键对象与数据流,解释“你从没分过「谁负责监听端口、解析 HTTP 报文」和「谁负责跑业务路由」。”,并用源码位置、日志或 Trace 标注证据。
- 为“Python(13) - Web 后端概览 / WSGI:同步时代的「请求处理函数签名」”设计正常与异常输入,验证“WSGI(Web Server Gateway Interface)是 Python 同步时代的接口标准。”,输出首个偏差位置与回归测试结果。
- 实现“Python(13) - Web 后端概览 / ASGI:异步时代的接口,补上了 WSGI 的短板”的最小代码或配置,检验“随着 WebSocket、SSE、async/await 流行,同步的 WSGI 不够用了,社区推出了 ASGI(Asynchronous Server Gateway Interface),是 WSGI 的「异步升级版」。”,输出命令、结果与 Diff,并说明不适用边界。
你在 node 里
app.listen(3000)一行就既起了服务器又跑了框架,从没分过家。进了 Python 后端世界,第一件要拧过来的事是:「Web 服务器」和「你的应用框架」是两个东西,中间靠一份叫 WSGI/ASGI 的「接口契约」对接。这篇先把这套地基讲清,再帮你在 Flask / Django / FastAPI 三选一里站好队——后面阶段三全程会用 FastAPI。
一、先建直觉:node 把服务器和框架揉成了一坨
在前端/node 的世界里,Express 给你的体感是「框架即服务器」:
// node + Express:一份代码,既是框架又是服务器
const express = require('express')
const app = express()
// 注册一个路由处理函数
app.get('/hello', (req, res) => {
res.send('Hello')
})
// app.listen 直接监听端口——服务器也是它起的
app.listen(3000)
你从没分过「谁负责监听端口、解析 HTTP 报文」和「谁负责跑业务路由」。因为 node 自带的 http 模块就是服务器,Express 只是在它上面包了一层,两者天然长在一起。
边界(这里和 node 不一样):Python 后端世界里,这两件事是刻意分开的:
- Web 服务器(也叫应用服务器):负责监听端口、收发 TCP、把原始 HTTP 报文解析成结构化数据,再把响应写回去。代表:
gunicorn、uvicorn、uWSGI。 - Web 框架:负责路由、参数解析、业务逻辑、生成响应。代表:
Flask、Django、FastAPI。
两者之间需要一份标准接口契约来对接,这份契约就是 WSGI / ASGI。框架按契约暴露一个「应用对象」,服务器按契约去调用它。
【node 心智模型】 【Python 心智模型】
┌───────────────────┐ ┌──────────┐ WSGI/ASGI ┌──────────┐
│ Express │ │ gunicorn │ ←──契约对接──→ │ Flask │
│ (服务器+框架一体) │ │ /uvicorn │ │ /FastAPI │
└───────────────────┘ │ (服务器) │ │ (框架) │
└──────────┘ └──────────┘
为什么要拆?因为这样框架和服务器可以自由组合、各自独立演进。你写的 Flask 应用,开发时用 Flask 自带的简易服务器跑,上线时换成性能更强的 gunicorn 跑——业务代码一行不用改。这正是「接口契约」解耦带来的好处,和 JS 里「面向接口编程」是同一种思想。
二、WSGI:同步时代的「请求处理函数签名」
WSGI(Web Server Gateway Interface)是 Python 同步时代的接口标准。说白了它就规定了一件事:框架要暴露一个长成固定样子的「可调用对象」,服务器照着这个样子去调它。
类比:就像 node 约定了 (req, res) => {} 这个回调签名,WSGI 约定了 Python 这边的「请求处理函数」长什么样:
并排看等价的 node 裸 http:
// node 裸 http:与 WSGI 一一对应
const http = require('http')
http.createServer((req, res) => {
// 对应 start_response:先写状态码和响应头
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
// 对应 return [b'...']:写响应体
res.end('Hello')
}).listen(3000)
你平时写 Flask 时不会手写这个函数——框架帮你把路由层封装好了,但它内部最终就是向服务器暴露这么一个 WSGI 可调用对象。
WSGI 的关键限制:它是同步模型。一次请求进来,处理函数从头跑到尾、返回结果,期间这个工作进程/线程被占住。要扛并发,只能靠「多开进程 / 多开线程」(这正是 gunicorn 默认干的事)。它天生不支持 async/await、WebSocket、SSE 这类长连接。
| 概念 | node | WSGI |
|---|---|---|
| 请求处理签名 | (req, res) => {} |
def app(environ, start_response) |
| 请求信息从哪拿 | req 对象 |
environ 字典 |
| 怎么发响应头 | res.writeHead() |
start_response() |
| 怎么发响应体 | res.end(body) |
return [b"..."] |
| 并发模型 | 单线程事件循环(天生异步) | 同步,多进程/多线程扛并发 |
三、ASGI:异步时代的接口,补上了 WSGI 的短板
随着 WebSocket、SSE、async/await 流行,同步的 WSGI 不够用了,社区推出了 ASGI(Asynchronous Server Gateway Interface),是 WSGI 的「异步升级版」。
ASGI 应用是一个
async函数。关于async/await的完整心智模型——它和 JS 单线程事件循环高度相似——详见第 17 篇《异步与并发》,这里只需先眼熟它长什么样。
你同样不会手写这个——FastAPI 帮你全封装了。但理解「FastAPI 是个 ASGI 应用、所以天生支持 async 和长连接」这件事很重要。
WSGI vs ASGI 一句话总结:
| 维度 | WSGI(旧/同步) | ASGI(新/异步) |
|---|---|---|
| 函数形态 | 普通 def |
async def |
| 并发模型 | 同步,靠多进程/线程 | 异步事件循环,单进程扛大量 IO 并发 |
| 长连接 | ❌ 不支持 WebSocket/SSE | ✅ 原生支持 |
| 代表服务器 | gunicorn、uWSGI | uvicorn、hypercorn |
| 代表框架 | Flask、老版 Django | FastAPI、Starlette、新版 Django |
| node 类比 | 多进程 PM2 跑同步代码 | node 原生事件循环 |
关键澄清(防止套用 JS 心智模型踩坑):Python 的
async和 JS 一样是「单线程事件循环」,它擅长的是 IO 密集型并发(等数据库、等网络),不是靠多核并行算 CPU。Python 还有个 GIL(全局解释器锁)的话题,会限制多线程的 CPU 并行——但那是另一个机制层面的话题,和 async 不是一回事,这里先不展开。记住一句:async 解决的是「等待时别干站着」,不是「用满 CPU 多核」。
四、三大框架选型:Flask / Django / FastAPI
这是本篇的实战落点。三个框架对应前端世界三种你熟悉的形态:
| 框架 | 一句话定位 | 前端类比 | 接口标准 |
|---|---|---|---|
| Flask | 极简微框架,给你路由和请求对象,其余自己拼 | Express(minimal,啥都自己装) | WSGI(同步为主) |
| Django | 全家桶大而全,自带 ORM/后台/认证/模板 | Nest.js / Rails(约定优于配置的重型框架) | WSGI(新版支持 ASGI) |
| FastAPI | 现代异步框架,类型驱动、自动生成文档 | Express + zod + Swagger 自动化 | ASGI(原生异步) |
4.1 Flask:Express 式的极简
// 等价的 Express
const app = express()
app.get('/hello', (req, res) => res.send('Hello Express'))
特点:核心极小,数据库、表单校验、认证都靠装第三方扩展自己搭。自由度高,但啥都得自己选型拼装——和 Express 生态一个味道。
4.2 Django:Nest.js 式的全家桶
Django 是「一站式」框架,自带 ORM、管理后台、用户认证、模板引擎、表单系统。你不用东拼西凑,但要接受它的「约定」和较陡的入门曲线。
特点:功能齐全、约定强、适合内容型/管理型大项目(博客、CMS、后台系统)。自带的 Admin 后台是杀手锏——几行配置就有一个能增删改查的管理界面。类比 Nest.js 那种「模块化、约定优于配置」的重量级体验。
4.3 FastAPI:现代异步 + 类型驱动 + 自动文档
FastAPI 是这条学习线的主角。它把「类型注解」用到了极致:你用类型声明参数,它就自动帮你做参数校验、数据序列化、生成交互式 API 文档。
并排看前端你会做的等价事:
// 等价的 Express + zod:你要手动校验、手动写文档
import { z } from 'zod'
const ItemSchema = z.object({ name: z.string(), price: z.number() })
app.post('/items', (req, res) => {
const item = ItemSchema.parse(req.body) // 手动校验
res.json({ name: item.name, price: item.price })
})
// Swagger 文档?还得另外装插件、写注解……
FastAPI 的核心爽点:上面那段 Python,校验自动做了,OpenAPI/Swagger 文档自动生成了(启动后访问 /docs 就有一个能点能调的交互页面),全靠类型注解驱动。这对前端工程师极友好——它把你熟悉的「类型即文档、类型即校验」哲学做进了框架。
五、怎么选?给前端新手的决策建议
| 你的场景 | 推荐 | 理由 |
|---|---|---|
| 学习 / 现代 API 服务 / AI 应用后端 | FastAPI | 异步、类型驱动、自动文档,前端心智最顺滑 |
| 内容/管理型大站、要自带后台和 ORM | Django | 全家桶省事,Admin 后台是杀手锏 |
| 极简脚本级 Web 服务、想完全自己掌控 | Flask | 轻、灵活、生态成熟 |
| 需要 WebSocket / SSE / 高 IO 并发 | FastAPI | ASGI 原生支持长连接与异步 |
本学习线选 FastAPI,原因有三:① 它是 ASGI,契合 AI 时代大量「等模型返回」的 IO 密集场景(流式输出、SSE);② 类型驱动 + 自动文档,前端工程师上手几乎零摩擦;③ 后面阶段五调大模型、做 RAG/Agent,配 FastAPI 起服务是社区主流组合。
前向索引(消除悬空感):从第 14 篇起进入 FastAPI 实操——第 14 篇路由与请求响应(对比 Express),第 15 篇用 Pydantic 做参数校验(≈ zod/TS interface),第 16 篇 SQLAlchemy 操作数据库,第 17 篇讲清
async/await的完整机制。本篇出现的async def、BaseModel现在只需眼熟,不必深究。
六、前端新手最易踩的坑
-
以为框架 = 服务器:在 node 里
app.listen一把梭,到 Python 会找不到「listen 在哪」。正解:业务代码里没有 listen,启动靠单独的服务器命令。比如 FastAPI 用uvicorn main:app,Flask 上线用gunicorn。开发框架和运行服务器是两层。# 启动 FastAPI 应用:用 uvicorn 这个 ASGI 服务器去跑 main.py 里的 app 对象 # main:app —— 冒号前是模块名(main.py),冒号后是应用实例变量名(app) uvicorn main:app --reload # --reload:改代码自动重启,≈ nodemon # 生产环境常见组合:gunicorn 管多进程,uvicorn 作为 worker 跑 ASGI gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker -
把 async 当成「自动变快/多核并行」:async 只在「有等待」(IO)时才省时间;在
async def里写一段纯 CPU 死循环,照样把事件循环卡死。机制详见第 17 篇。 -
在 async 路由里调同步阻塞代码:比如在 FastAPI 的
async def里直接调一个会阻塞的老式数据库驱动或time.sleep,会卡住整个事件循环——和 node 里在主线程跑同步重活阻塞所有请求是同一个道理。要么用异步库,要么把阻塞活儿丢到线程池。 -
选型时无脑上 Django:Django 大而全,但它的 ORM、项目结构是强约定,学习曲线陡。只是想撸个 API,Django 的「全家桶」反而是负担——这种场景 FastAPI 更轻更顺。
-
混淆 WSGI 服务器跑 ASGI 应用:用
gunicorn main:app直接跑 FastAPI(ASGI 应用)会报错,因为 gunicorn 默认是 WSGI 服务器。要么用 uvicorn,要么给 gunicorn 指定-k uvicorn.workers.UvicornWorker这个 ASGI worker。
七、总结
- 先建直觉:node 把服务器和框架揉成了一坨:在前端/node 的世界里,Express 给你的体感是「框架即服务器」:
- WSGI:同步时代的「请求处理函数签名」:WSGI(Web Server Gateway Interface)是 Python 同步时代的接口标准。
- ASGI:异步时代的接口,补上了 WSGI 的短板:随着 WebSocket、SSE、async/await 流行,同步的 WSGI 不够用了,社区推出了 ASGI(Asynchronous Server Gateway Interface),是 WSGI 的「异步升级版」。
- 三大框架选型:Flask / Django / FastAPI:| Django | 全家桶大而全,自带 ORM/后台/认证/模板 | Nest.js / Rails(约定优于配置的重型框架) | WSGI(新版支持 ASGI) |
- 怎么选?给前端新手的决策建议:| 内容/管理型大站、要自带后台和 ORM | Django | 全家桶省事,Admin 后台是杀手锏 |
- 前端新手最易踩的坑:以为框架 = 服务器:在 node 里 app.listen 一把梭,到 Python 会找不到「listen 在哪」。 -> 把 async 当成「自动变快/多核并行」:async 只在「有等待」(IO)时才省时间; -> 在 async 路由里调同步阻塞代码:比如在 FastAPI 的 async def 里直接调一个会阻塞的老式数据库驱动或 time.sleep,会卡住整个事件循环——和 node 里在主线程跑同步重活阻塞所有请求是同一个道理。 -> 选型时无脑上 Django:Django 大而全,但它的 ORM、项目结构是强约定,学习曲线陡。
学完自测
选择所有正确答案;提交后逐项核对判断依据。