前面我们学习了如何用 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 的完整流程
- Web 服务器(如 Gunicorn、wsgiref)收到 HTTP 请求。
- 服务器解析 HTTP 请求报文,构造一个
environ字典,写入相关数据(如HTTP_HOST、QUERY_STRING等)。 - 服务器调用应用程序
app(environ, start_response)。 - 应用程序内部:
- 从
environ中提取需要的参数。 - 调用
start_response(status, headers)设置响应状态和头。 - 返回可迭代的响应体。
- 服务器将应用程序返回值组合成完整的 HTTP 响应发送给客户端。
- 服务器继续循环,处理下一个请求。
为何需要 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 的定义方式会让你感觉不到 environ 和 start_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 开发的底层基石,日后学习任何框架都会看到熟悉的影子。