当前位置 : 首页 » 文章分类 :  开发  »  Python-Web

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服务器

https://gunicorn.org/

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-异步

阅读
评论
3.1k
阅读预计12分钟
创建日期 2025-09-02
修改日期 2025-09-02
类别

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论