人人都会AI编程

17.4 简单 Web 服务实现、WSGI 协议原理

更新时间:2026-07-12

前面我们学习了如何用 socket 编写 TCP 服务器,也掌握了 requests 等客户端库的用法。但真要写一个能处理 HTTP 请求、返回动态内容的 Web 服务,你会希望有一个更规范的抽象,而不是每一次都手工解析 HTTP 报文。这就是 WSGI 要解决的问题。

WSGI 是什么?

WSGI(Web Server Gateway Interface) 是 Python 中定义 Web 服务器与 Web 应用程序之间通信的一种标准接口。你可以把它理解为“Web 服务器和 Python Web 应用之间的约定”:只要双方都遵守 WSGI 规范,就可以自由替换服务器(如 Gunicorn、uWSGI)或框架(如 Flask、Django),而不用修改代码。

它的核心思想很简单:

  • 应用程序是一个可调用对象(通常是一个函数),接收两个参数:
  • environ:一个字典,包含了请求相关的所有信息(请求方法、路径、查询参数、请求头等,类似于 CGI 环境变量)。
  • start_response:一个回调函数,用于设置响应状态码和响应头。
  • 应用程序的返回值是一个可迭代的字节串列表,代表响应体内容。

WSGI 实际上是 同步 的协议(后来有 ASGI 用于异步),但直到现在它仍然是绝大多数 Python Web 应用的基础。

一个最简单的 WSGI 应用

下面用最原始的方式(标准库里的 wsgiref 内置的简易服务器)来演示:

# simple_wsgi_app.py

def application(environ, start_response):
    # 获取请求方法、路径等
    method = environ['REQUEST_METHOD']
    path = environ['PATH_INFO']

    # 构造响应体
    body = f"<h1>Hello from WSGI</h1><p>Method: {method}</p><p>Path: {path}</p>"
    
    # 设置状态码和响应头(注意:响应头是列表,每个元素是 (name, value) 元组)
    status = '200 OK'
    headers = [('Content-Type', 'text/html; charset=utf-8'),
               ('Content-Length', str(len(body.encode('utf-8'))))]
    
    start_response(status, headers)
    
    # 返回一个可迭代对象(这里只返回一个元素)
    return [body.encode('utf-8')]

然后使用 Python 自带的 wsgiref.simple_server 运行它:

# server.py
from wsgiref.simple_server import make_server
from simple_wsgi_app import application

if __name__ == '__main__':
    server = make_server('127.0.0.1', 8000, application)
    print("Serving on http://127.0.0.1:8000 ...")
    server.serve_forever()

运行后,用浏览器访问 http://127.0.0.1:8000/hello,你会看到页面显示当前方法(GET)和路径(/hello)。这就是一个最基础的 WSGI 应用。

WSGI 的完整流程

  1. Web 服务器(如 Gunicorn、wsgiref)收到 HTTP 请求。
  2. 服务器解析 HTTP 请求报文,构造一个 environ 字典,写入相关数据(如 HTTP_HOSTQUERY_STRING 等)。
  3. 服务器调用应用程序 app(environ, start_response)
  4. 应用程序内部:
  • environ 中提取需要的参数。
  • 调用 start_response(status, headers) 设置响应状态和头。
  • 返回可迭代的响应体。
  1. 服务器将应用程序返回值组合成完整的 HTTP 响应发送给客户端。
  2. 服务器继续循环,处理下一个请求。

为何需要 WSGI?

  • 解耦:框架开发者只需专注于生成一个符合 WSGI 的可调用对象,不需要关心底层是如何接收 HTTP 连接的。服务器开发者只需知道如何调用一个 WSGI 应用,不用关心应用内部逻辑。
  • 可替换:你可以把在开发时用 wsgiref 跑的应用,部署时换成性能更高的 Gunicorn 或 uWSGI,一行代码都不改。
  • 中间件:WSGI 的另一个重要概念是中间件(Middleware)。中间件本身也是一个 WSGI 应用,它可以包装另一个应用,在请求/响应流经的时候添加额外功能(如请求日志、权限校验、压缩等)。比如:
class SimpleMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        print(f"Request: {environ['REQUEST_METHOD']} {environ['PATH_INFO']}")
        response = self.app(environ, start_response)
        # 可以在这里对响应做处理
        return response

使用时,用 app = SimpleMiddleware(app) 包装原来的应用即可。

从 WSGI 到 Web 框架

真正的 Web 框架(如 Flask、Django)本质上就是在 WSGI 的基础上,为你提供了更简单、功能更丰富的接口。比如 Flask 的定义方式会让你感觉不到 environstart_response 的存在:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>Hello Flask</h1>'

但它的底层执行逻辑仍是:Flask 内部封装了路由、请求对象、响应对象等,最终暴露出来的仍然是一个符合 WSGI 的可调用对象 app,同样可以用 Gunicorn 运行。

实用性说明

  • 快速开发调试:标准库的 wsgiref 仅适用于开发测试,单进程、单线程,性能很低,绝对不能用于生产环境
  • 生产部署:真正上线时,你需要采用生产级 WSGI 服务器,最常用的是 Gunicorn(Unix 系统),配合 Nginx 反向代理使用,使配置更加高效和稳定。
  • ASGI 的演进:如果应用需要处理 WebSocket、长连接等异步功能,WSGI 的同步模型就不够了。这时你需要 ASGI(Asynchronous Server Gateway Interface)和异步框架(如 FastAPI),这部分我们会在后续章节深入。

掌握了 WSGI 的基本原理,你就能理解 Python Web 开发的底层基石,日后学习任何框架都会看到熟悉的影子。