F-02 Flask 全栈开发 · 02 —— Web 应用的本质与 WSGI 协议

本文试图回答三个问题:  

1. “Web 应用”到底在做什么?  

2. 为什么 Python 需要 WSGI?  

3. WSGI 具体长什么样?我们如何利用它?

一、Web 应用的本质


1. HTTP 请求–响应模型  

   • 浏览器把 HTTP 报文(URL、Method、Header、Body)发给一台服务器。  

   • 服务器返回新的 HTTP 报文(Status-Line、Header、Body)。  

   • “Web 应用”负责生成这个响应报文的内容。  

   • 整个过程是 无状态 的:一次请求完成后,TCP 连接通常就被关闭。

2. 静态 VS 动态  

   • 静态:Nginx/Apache 直接把磁盘上的 PNG、CSS 原封不动传给客户端。  

   • 动态:需要程序根据请求参数/数据库内容现算出 HTML/JSON,再返回。

     这就是我们写 Flask、Django、Rails、Express 的原因。

3. 三个角色  

   a) Web Server(Nginx、Apache、Gunicorn、uWSGI…)  

   b) Web Application(Flask/Django/PHP/Node…)  

   c) 协议 & 接口(FastCGI、Servlet、Rack、WSGI…)  

   本质:让 Server 能调用 Application,并把 HTTP 信息在两者之间正确搬运。

二、为什么要有 WSGI


1. 历史:一团乱麻  

   早期 Python Web 框架各搞各的(CGI、FastCGI、mod_python、Zope…),

   服务器和框架强耦合,无法互换:

   ┌────────┐  mod_python  ┌──────────┐

   │ Apache │ ───────────> │  Django  │

   └────────┘              └──────────┘

   想把 Apache 换成 Nginx?抱歉,不支持。

2. 需求:定义一个“最小公共接口” 

   • 只传递 HTTP 所需最基本的信息;  

   • 不依赖任何框架、服务器实现;  

   • 简单到可以用几个函数就实现;  

   • 留出中间件的空间。

3. 结果:PEP 333 / PEP 3333 — Web Server Gateway Interface (WSGI)   2003–2010,成为 Python Web 事实标准。  

   从此:

   - Gunicorn、uWSGI、Waitress 等 WSGI Server 负责 Socket + Protocol  

   - Flask、Django、FastAPI、Bottle 等 WSGI Application 负责 业务逻辑

   二者可以自由组合。

三、WSGI 协议长什么样


1. 规则(最小可行):  

   • Web 应用必须是 可调用对象 (callable):函数、方法、类实例皆可。  

   • 可调用签名:`application(environ, start_response) -> iterable`  

           - `environ`:一个 dict,装满了 CGI 风格的键值对。  

             例如:`REQUEST_METHOD`, `PATH_INFO`, `QUERY_STRING`,  以及所有 HTTP_ 前缀的 Header。  

           - `start_response(status, headers)`:回调函数,由 Server 提供。  

                     • status: `"200 OK"`  

                     • headers: `[("Content-Type","text/html")]`  

           - 返回值:一个可迭代对象(通常是 list/tuple 或 generator),

             其元素必须是 bytes,Server 将把它们逐块写到 TCP 连接。

2. 最小 demo

# hello.py

def application(environ, start_response):

    msg = b"Hello, WSGI!"

    start_response("200 OK", [("Content-Type", "text/plain"),

                              ("Content-Length", str(len(msg)))])

    return [msg]

3. 不依赖任何第三方 Server 也能跑

# server.py
from wsgiref.simple_server import make_server

from hello import application

httpd = make_server("0.0.0.0", 8000, application)
print("Serving on http://127.0.0.1:8000")
httpd.serve_forever()

4. Flask/Django 只是包装  

   Flask 对外暴露的 `app = Flask(__name__)` 本质上就是 `application`。  

   gunicorn -w 4 "myapp:create_app()"
                          │
                          ▼
   Gunicorn master  ===>  4 worker  ===>  Flask wsgi_app()

   • Gunicorn 做多进程/线程,负责 Socket。  

   • 调用 Flask 的 `wsgi_app(environ,start_response)`。  

   • Flask 内部再创建 Request/Context、路由匹配、模板渲染。  

   • 得到 Response,Gunicorn 写回客户端。

四、WSGI 中间件


链式调用示意:

Server ──► Middleware A ──► Middleware B ──► Application

        ◄──────────────────────────────────────────────◄

典型用途:  

- 统一日志/Trace ID  

- 压缩 GZip  

- 静态文件代理  

- 统一错误页  

Gunicorn、Werkzeug、Rollbar/Sentry 均提供现成 WSGI 中间件。

五、WSGI 的局限 & 未来


1. 阻塞:单条请求执行期间线程被占用,无法原生异步。  

2. WebSocket:不是基于 HTTP 请求-响应模型,WSGI 无法胜任。  

3. 解决方案:ASGI(Asynchronous Server Gateway Interface, PEP 484)。  

   • 支持 async/await、WebSocket、HTTP2。  

   • 对标 FastAPI / Starlette / Django 3+ async。  

   • 思想与 WSGI 相同,只是把调用协议改为异步。

六、总结


Web 应用的本质:  

“Server 负责 连接,框架负责 内容,中间靠 协议接口 说话。”

WSGI 关键 3 件事:  

1. `environ` 输入字典  

2. `start_response()` 回调  

3. `bytes iterable` 输出

七、 补充


F-02 Flask 全栈开发 · 02 —— Web 应用的本质与 WSGI 协议 —— 补充-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值