flask入门(五)WSGI及其Python实现
文章目录
- WSGI(Web Server Gateway Interface)
- 基于WSGI实现的Flask框架
- 生产环境中的WSGI
- 参考文献
WSGI(Web Server Gateway Interface)
WSGI:Python Web 应用(Flask、Django、FastAPI 等)与 Web 服务器(Gunicorn、uWSGI、mod_wsgi 等)之间的标准协议
为什么需要 WSGI?
- Nginx / Apache → 负责接收浏览器的 HTTP 请求
- Flask / Django → 负责写业务逻辑,返回 HTML/JSON
❌ 问题:Nginx 并不能直接“调用” Python 代码,它只会转发 HTTP 请求
✅ 解决:定义一个“桥梁”—— WSGI 协议
浏览器←\leftarrow←HTT→\to→Nginx/Apache←\leftarrow←WSGI→\to→Gunicorn/uWSGI←\leftarrow←Python→\to→Flask/Django
WSGI应用本质上是一个Python可调用对象(通常是函数或类的实例),它必须接受两个参数
environ
:一个包含请求数据的Python字典start_response
:一个用于发送HTTP状态和头信息的回调函数
这个接口设计得非常简单,只要求Web开发者实现一个函数,就可以响应HTTP请求
WSGI是一个低级接口,许多Python开发者在使用Django、Flask等流行框架时,实际上是在WSGI之上构建应用
最基础的WSGI应用实现
def application(environ, start_response):"""一个简单的WSGI应用"""# 设置HTTP响应状态和头信息status = '200 OK'headers = [('Content-Type', 'text/plain; charset=utf-8')]# 调用start_response发送响应头start_response(status, headers)# 获取请求路径path = environ.get('PATH_INFO', '').lstrip('/')# 根据路径返回不同内容if path == '':return [b'Welcome to WSGI application!']elif path == 'hello':return [b'Hello, WSGI World!']else:start_response('404 Not Found', [('Content-Type', 'text/plain')])return [b'404 Not Found']# 运行WSGI服务器
if __name__ == '__main__':from wsgiref.simple_server import make_serverhttpd = make_server('', 8000, application)print("Serving on port 8000...")httpd.serve_forever()
- WSGI应用函数:application函数是核心,它接收
environ
和start_response
两个必需参数 environ
字典:包含所有请求信息,如HTTP方法、路径、头信息等。可以通过environ.get('PATH_INFO')
获取请求路径start_response
函数:用于设置HTTP响应状态和头信息。它需要两个参数:状态字符串(如'200 OK'
)和头信息列表(如[('Content-Type', 'text/plain')]
)- 响应体:必须是一个字节字符串的可迭代对象(通常是列表),如
[b'Hello, WSGI!']
- WSGI服务器:使用Python标准库中的
wsgiref
模块创建一个简单的WSGI服务器来运行我们的应用
实际工作流程
- 当用户访问服务器时,WSGI服务器接收HTTP请求
- 服务器将请求信息转换为
environ
字典 - 服务器调用WSGI应用函数,传入
environ
和start_response
- WSGI应用处理请求,调用
start_response
设置响应头 - WSGI应用返回响应体(字节字符串列表)
- 服务器将响应发送回客户端
基于WSGI实现的Flask框架
前置知识
- Flask入门(一)
- Flask入门(二)模板
- flask入门(三)静态文件
Flask框架本身就是构建在WSGI规范之上的,每个Flask应用实例本质上就是一个符合WSGI规范的可调用对象
在Flask内部,Flask类实现了WSGI接口
- Flask应用实例是一个可调用对象(实现了
__call__
方法) - 当WSGI服务器调用该实例时,会传入
environ
和start_response
参数→\to→app(environ, start_response)
可以被服务器调用 - Flask内部处理请求,生成响应,并返回符合WSGI规范的响应体
基本Flask应用(标准用法):
from flask import Flask, requestapp = Flask(__name__)@app.route('/')
def home():return 'Hello from Flask!'@app.route('/user/<username>')
def show_user_profile(username):return f'User: {username}'@app.route('/query')
def query_example():name = request.args.get('name', 'Guest')return f'Hello, {name}!'if __name__ == '__main__':app.run(debug=True, host='0.0.0.0', port=5000)
- 用 Flask 内置服务器(调试)
python app.py
Flask 内部还是调用 WSGI 接口,只是用内置开发服务器封装了一层
但在生产环境下如果用 nohup python app.py&
之类运行,Ctrl+C后台挂起/终端断开/内存不足时进程会挂掉。
- 方式 B:用原生 WSGI 服务器启动
# wsgi_server.py
from wsgiref.simple_server import make_server
from app import app # app就是Flask实例,也是WSGI应用httpd = make_server('', 5000, app) # 这里app直接当WSGI应用传入
print("Serving Flask on port 5000...")
httpd.serve_forever()
- 方式 C:用 Gunicorn 启动
gunicorn -w 4 -b 0.0.0.0:5000 app:app
生产环境中的WSGI
在实际生产环境中,我们通常不会使用wsgiref
这样的简单服务器,而是使用更强大的WSGI服务器如Gunicorn
或uWSGI
,它们能处理更多并发请求并提供更好的性能
# 使用Gunicorn运行Flask应用
gunicorn -w 4 -b 0.0.0.0:5000 app:app
gunicorn
:启动 Gunicorn 服务器的命令-w 4
:表示 worker 数量,每个 worker 是一个独立的 Python 进程(不是线程),可以并发处理多个请求,多 worker 能更好利用多核 CPU-b 0.0.0.0:5000
:表示绑定地址和端口→\to→服务地址是http://服务器IP:5000/
app:app
:模块名:应用对象- 第一个 app → Python 文件名(不带 .py),即
app.py
- 第二个 app → 文件里的 Flask 应用对象
- 第一个 app → Python 文件名(不带 .py),即
参考文献
- Web服务器网关接口
- What is WSGI (Web Server Gateway Interface)
- The Definitive Guide to WSGI