Python-Web
Python Web 开发笔记
WSGI Web服务网关接口
PEP 3333 – Python Web Server Gateway Interface v1.0.1
https://peps.python.org/pep-3333/
WSGI(Web Server Gateway Interface)
WSGI 的核心目标是定义一个简单、通用的接口,使得任何兼容 WSGI 的 Web 应用(或框架)可以运行在任何兼容 WSGI 的 Web 服务器上。
WSGI 实现了 Web 服务器 和 Python Web 应用程序/框架 之间的解耦。
WSGI 应用的核心是一个 可调用对象(通常是一个函数,或定义了 __call__
方法的对象),这个可调用对象接受两个参数:
environ
一个字典,包含所有 HTTP 请求的环境变量(如请求方法、路径、查询字符串等)。start_response
一个可调用函数,用于发起 HTTP 响应(设置状态码和响应头)。
environ 请求信息字典environ
是个字典,包含了所有与 HTTP 请求相关的信息
如请求方法、路径、查询字符串等(如 REQUEST_METHOD, PATH_INFO, QUERY_STRING, HTTP_* 头信息)
以及一些 WSGI 特定的键(如 wsgi.input 用于请求体,wsgi.errors 用于错误输出)
start_response 响应回调函数start_response
用于开始 HTTP 响应的回调函数。
应用必须调用 start_response
来开始发送 HTTP 响应。
start_response
接受两个参数:
status
HTTP 状态字符串,如 “200 OK”response_headers
一个由(header_name, header_value)
元组组成的列表
start_response
返回一个可迭代对象(通常是函数本身,但也可以是其他可迭代对象),用于写入响应体。
Web服务器+WSGI应用工作流程
1、Web 服务器(如 Apache + mod_wsgi, Nginx + uWSGI/gunicorn)接收到一个 HTTP 请求
服务器根据配置,将请求信息转换为 environ 字典,并准备好 start_response 函数
服务器调用 WSGI 应用的可调用对象,传入 environ 和 start_response
2、WSGI 应用中
处理请求(读取 environ)
调用 start_response(status, headers)
返回一个可迭代对象(如字符串列表、生成器),其中包含响应体内容
3、服务器接收状态码和头部,发送 HTTP 响应头
服务器迭代应用返回的可迭代对象,将每个块作为响应体发送给客户端
4、服务器关闭连接或准备处理下一个请求
WSGI 应用示例
def simple_app(environ, start_response):
"""最简单的 WSGI 应用"""
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [b'Hello World!']
# 使用内置的 wsgiref 服务器运行
if __name__ == '__main__':
from wsgiref.simple_server import make_server
server = make_server('localhost', 8000, simple_app)
print("Server running on http://localhost:8000")
server.serve_forever()
WSGI 中间件
WSGI 中间件也是一个 WSGI 应用,它“包裹”原 WSGI 应用。
中间件常用来实现:
- 修改 environ(例如,添加解析后的 cookie 信息)
- 处理或修改 start_response 的参数(例如,添加默认响应头)
- 处理或修改响应体(例如,压缩内容)
- 在调用下层应用之前或之后执行操作(例如,记录请求时间、身份验证、会话管理)
- 甚至完全不调用下层应用(例如,直接返回 403 Forbidden)
WSGI 日志记录中间件示例:
class LoggingMiddleware:
"""WSGI 中间件示例:记录请求日志"""
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
import time
# 记录请求开始时间
start_time = time.time()
method = environ['REQUEST_METHOD']
path = environ['PATH_INFO']
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {method} {path}")
# 包装 start_response 来记录响应状态
def logging_start_response(status, headers):
end_time = time.time()
duration = (end_time - start_time) * 1000 # 转换为毫秒
print(f"Response: {status} ({duration:.2f}ms)")
return start_response(status, headers)
return self.app(environ, logging_start_response)
# 使用中间件包装应用
app_with_logging = LoggingMiddleware(advanced_wsgi_app)
WSGI 的问题
同步阻塞
WSGI 核心模型是同步的。如果一个请求的处理需要等待 I/O(如慢速数据库查询、调用外部 API),处理该请求的工作线程/进程会被阻塞,无法处理其他请求。虽然可以通过增加工作进程/线程数来提高并发能力,但这会消耗大量内存和 CPU 上下文切换开销,难以应对超高并发(C10K+ 问题)
协议限制
原生 WSGI 设计主要针对 HTTP 请求/响应周期。它不支持处理需要长连接或双向通信的协议,如 WebSocket 或 HTTP/2 Server Push
ASGI 异步服务网关接口
ASGI Documentation
https://asgi.readthedocs.io/en/latest/
ASGI(Asynchronous Server Gateway Interface)
ASGI 是对 WSGI 的异步扩展,于 2016 年左右被提出,提供原生异步支持,支持更多协议,特别是 HTTP、HTTP/2 和 WebSocket
ASGI 介于网络协议服务和 Python 应用之间的标准接口,能够处理多种通用的协议类型,包括 HTTP,HTTP2 和 WebSocket。
ASGI 应用的核心是一个异步可调用对象(通常是一个 async
函数或一个定义了 async def __call__
方法的对象),它接受三个参数:
scope
字典,包含连接信息(如协议类型、路径、头等)receive
异步函数,用于接收客户端事件(如 HTTP 请求、WebSocket 消息)send
异步函数,用于发送事件给客户端(如响应、WebSocket 数据)
scope
请求信息scope
是一个字典,包含连接的类型(type,如 “http”, “websocket”)以及该类型连接的相关信息(如 HTTP 请求的路径、方法、头部;WebSocket 的连接路径等)。它类似于 WSGI 的 environ,但结构更清晰且协议无关。
receive
异步接收函数async def receive() -> dict
应用调用它来从客户端接收事件/消息(如 HTTP 请求体数据块、WebSocket 接收到的消息)。
WebSocket 生命周期中 receive()
可能接收到:
- 连接请求
{'type': 'websocket.connect'}
- 消息接收
{'type': 'websocket.receive', 'text': '...'/'bytes': b'...'}
- 连接关闭
{'type': 'websocket.disconnect', 'code': ...}
send
异步发送函数async def send(event: dict) -> None
应用调用它向客户端发送事件/消息(如 HTTP 响应头、响应体数据块、WebSocket 发送的消息)。
send()
可以发送响应头数据:{'type': 'http.response.start', 'status': 200, 'headers': [...]}
也可以发送响应体数据:{'type': 'http.response.body', 'body': b'...', 'more_body': True/False}
WebSocket 生命周期中 send()
可以发送:
- 连接接受
{'type': 'websocket.accept'}
- 消息发送
{'type': 'websocket.send', 'text': '...'/'bytes': b'...'}
- 连接关闭
{'type': 'websocket.close', 'code': ...}
ASGI 的优势
ASGI 是异步优先的。
应用使用 async/await 语法处理 I/O 操作。当一个请求/连接进来时,服务器会创建一个“连接”任务(通常是一个 asyncio.Task)。
应用代码可以在等待 I/O(如数据库查询、网络请求)时挂起,让出控制权给事件循环,事件循环可以去处理其他连接的任务。
这使得单个进程/线程可以高效地处理成千上万的并发连接。
ASGI 应用工作流程
1、ASGI 服务器(如 Daphne, Uvicorn, Hypercorn)接收到一个 HTTP 请求
服务器确定连接类型 (“http”),构建 scope 字典。
服务器创建一个新的异步任务,调用 ASGI 应用的可调用对象,传入 (scope, receive, send)
2、ASGI 应用中async def app(scope, receive, send):
可能等待 receive()
来获取请求体数据(如果需要)
处理请求逻辑(可能涉及异步数据库调用等)
调用 await send({'type': 'http.response.start', ...})
发送响应头
调用一次或多次 await send({'type': 'http.response.body', ...})
发送响应体(支持流式响应)
3、服务器接收 send 调用发送的事件,将其转换为实际的网络数据发送给客户端。
4、应用任务完成,服务器清理资源
ASGI 应用示例
async def simple_asgi_app(scope, receive, send):
"""简单的 ASGI 应用"""
if scope['type'] == 'http':
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
],
})
await send({
'type': 'http.response.body',
'body': b'Hello ASGI World!',
})
# 使用 uvicorn 运行
# pip install uvicorn
# uvicorn script_name:simple_asgi_app --reload
Starlette ASGI应用框架
https://www.starlette.io/
https://github.com/encode/starlette
Starlette 是一个轻量级的 ASGI 框架/工具包,专为构建高性能的异步 Web 服务而设计。它是 FastAPI 的底层框架,提供了构建现代 Web 应用程序所需的核心功能。
FastAPI 基于 Starlette 构建,并在其基础上增加了数据验证、序列化、自动 API 文档生成等高级特性
特性:
- 轻量级 ASGI 框架/工具包
- 简洁、高效、可扩展,提供构建现代 Web 应用所需的基本组件
- 完全基于 Python 的 asyncio 库,支持异步编程
- 路由、请求处理、响应生成、中间件支持、WebSocket 支持等
使用示例
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn
async def homepage(request):
return JSONResponse({"message": "Hello, Starlette World!"})
async def user_endpoint(request):
user_id = request.path_params["user_id"]
return JSONResponse({"user_id": user_id})
# 定义路由
routes = [
Route("/", homepage),
Route("/user/{user_id:int}", user_endpoint)
]
# 创建应用实例
app = Starlette(routes=routes)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
Uvicorn ASGI服务器
pip install uvicorn
https://www.uvicorn.org/
https://github.com/encode/uvicorn
Uvicorn 是一个轻量级、高性能的 ASGI 服务器,专为运行异步 Python Web 应用而设计。它基于 uvloop 和 httptools 构建。
Uvicorn 支持 HTTP 和 WebSocket 协议,可以为 FastAPI、Starlette 等 ASGI 应用程序框架 提供高性能的运行环境。
特性:
- 轻量级、高性能的 ASGI 服务器
- 为异步 Python Web 应用(如 FastAPI、Starlette)提供极速的请求处理能力
- 基于 uvloop (替代 asyncio 事件循环,性能提升 2-4 倍 ) 和 httptools (高效的 HTTP 解析器)
- 支持 HTTP/1.1 和 WebSocket
- 支持热重载 (开发环境)、异步处理、高并发
ASGI 服务器负责:
- 接受客户端连接
- 解析 HTTP/WebSocket 协议
- 将请求转换为 ASGI 消息格式
- 调用 ASGI 应用处理请求
(scope, receive, send)
- 将应用响应发送回客户端
请求处理流程:
Client → Uvicorn (ASGI Server) → ASGI Application (FastAPI/Starlette)
Gunicorn WSGI服务器
Gunicorn (Green Unicorn) 是一个广泛使用的 Python WSGI HTTP 服务器,专为在生产环境中部署 Python Web 应用而设计。
特性:
- WSGI HTTP 服务器,用于生产环境部署
- 主从 (Master-Worker) 多进程模型,基于 预派遣 (Pre-fork) 模式
- 作为 WSGI 服务器,接收并处理 HTTP 请求,与 Python Web 应用交互,返回响应
- 高性能、低内存占用、易用、配置灵活、兼容性强
主从 (Master-Worker) 多进程模型
主进程 (Master Process) 不直接处理客户端请求
- 工作进程管理:启动、监控和终止工作进程。当工作进程异常退出时,主进程会重新生成新的进程,维护配置的工作进程数量(通过
-w
参数指定) - 监听套接字:绑定和管理网络端口,并将接入的连接分配给空闲的工作进程处理,实现负载均衡
工作进程 (Worker Process)
实际处理 HTTP 请求的进程,每个工作进程都是独立的,拥有自己的内存空间。
负责请求处理:解析 HTTP 请求,调用 WSGI 应用(如你的 Flask 或 Django 应用)处理请求,生成并返回 HTTP 响应
运行简单 WSGI 应用
# app.py - 简单的 WSGI 应用
def application(environ, start_response):
status = '200 OK'
headers = [('Content-Type', 'text/plain')]
start_response(status, headers)
return [b'Hello Gunicorn!']
# 运行命令
# gunicorn app:application
运行 Flask 应用
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello, Gunicorn!"
# 启动4个工作进程
# gunicorn -w 4 -b 0.0.0.0:8000 app:app
搭配 Uvicorn 使用
这是一种非常常见的使用模式,利用 Gunicorn 管理多个 Uvicorn 工作进程 (Worker)。
Gunicorn 负责进程管理、负载均衡和容错,而 Uvicorn Worker 负责高效的异步请求处理
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main_fastapi:app --bind 0.0.0.0:8000
-w
指定工作进程个数-k uvicorn.workers.UvicornWorker
指定每个工作进程使用 Uvicorn Worker
下一篇 JavaScript-异步
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: