代码语言

知识点思维导图

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 报文解析成结构化数据,再把响应写回去。代表:gunicornuvicornuWSGI
  • Web 框架:负责路由、参数解析、业务逻辑、生成响应。代表:FlaskDjangoFastAPI

两者之间需要一份标准接口契约来对接,这份契约就是 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 defBaseModel 现在只需眼熟,不必深究。


六、前端新手最易踩的坑

  1. 以为框架 = 服务器:在 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
    
  2. 把 async 当成「自动变快/多核并行」:async 只在「有等待」(IO)时才省时间;在 async def 里写一段纯 CPU 死循环,照样把事件循环卡死。机制详见第 17 篇。

  3. 在 async 路由里调同步阻塞代码:比如在 FastAPI 的 async def 里直接调一个会阻塞的老式数据库驱动或 time.sleep,会卡住整个事件循环——和 node 里在主线程跑同步重活阻塞所有请求是同一个道理。要么用异步库,要么把阻塞活儿丢到线程池。

  4. 选型时无脑上 Django:Django 大而全,但它的 ORM、项目结构是强约定,学习曲线陡。只是想撸个 API,Django 的「全家桶」反而是负担——这种场景 FastAPI 更轻更顺。

  5. 混淆 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、项目结构是强约定,学习曲线陡。

学完自测

选择所有正确答案;提交后逐项核对判断依据。

1在“Web 后端概览”中,需要同时满足“先建直觉:node 把服务器和框架揉成了一坨”与“WSGI:同步时代的「请求处理函数签名」”。给定正文约束“你从没分过「谁负责监听端口、解析 HTTP 报文」和「谁负责跑业务路由」。”,哪些判断保持了原有处理机制?多选
2“Web 后端概览”出现偏差:“在“Web 后端概览 / ASGI:异步时代的接口,补上了 WSGI 的短板”中,即使不满足“但理解「FastAPI 是个 ASGI 应用、所以天生支持 async 和长连接」这件事很重要”,结果与副作用仍会保持不变。”已成为实际行为。围绕“ASGI:异步时代的接口,补上了 WSGI 的短板”与“三大框架选型:Flask / Django / FastAPI”,哪些判断能定位被改变的职责或边界?多选
3评审“Web 后端概览”方案时,验收条件包含“核心极小,数据库、表单校验、认证都靠装第三方扩展自己搭。”。关于“Flask:Express 式的极简”与“Django:Nest.js 式的全家桶”的哪些决策符合正文机制?多选