1

前言

相信每个刚接触python web开发的同学,在学习flask、django这些框架的时候,肯定会被告知说正式环境部署时,不应该用框架自带的web服务器启动对外提供服务,而应该搭配专门的wsgi服务器(uwsgi、gunicorn等)提供服务,为什么?在这套推荐的部署方案中,wsgi服务器和咱们使用的框架都各自扮演着什么角色?本文将尽可能用大白话通俗易懂的讲清楚。

为什么需要wsgi

首先,先思考一个问题,一个http请求从客户端发起到处理完成需要进过哪些流程?
image.png
服务端的处理可以分为两部分:

  • 与客户端进行交互(接收并解析request,封装并发送response)
  • 根据request参数进行相关的处理

python将这两部分分开来,即有专门处理客户端交互的gateway框架。而flask、django这些web框架,则是专门用于进行请求逻辑处理的工作,称为application。

分开后,再看上图,步骤2、4、5是由gateway框架负责;步骤3由application负责。

大家都知道,pythoner圈里个个都是人才,说话又好听,技术还强的不行,很快就涌现出各种各样优秀的gateway框架和application框架了,那怎么能让这些框架实现“混搭”呢?
我们可以规定一个协议,或者说是一个对gateway框架和application的设计要求;规定gateway和application分别都要需要实现什么方法,方法要怎么调用;这样,当市面上出现一个更好的gateway框架时,我们可以零成本的将我们的application跟新的gateway搭配起来。

而这套协议,就是wsgi,简单说,它规定了gateway如何和application交互

wsgi具体是如何定义的

wsgi对于server端有以下要求:

1.提供一个接收客户端请求的服务

  1. 提供一个start_response函数,被application调用,start_response函数接收status和headers,用于设置响应状态和响应头部信息(def start_response(self, status, headers,exc_info=None):
  2. 将application返回的结果发送给客户端

Server端实现伪码

class WsgiServer:
    def __init__(self, host, port, app):
    def serve_forever(self):    # 启动监听端口服务,接收请求
    def start_response(self, status, headers):  # 用于被application调用,设置status和headers
        ...
        self.status = status
        self.headers = headers
        ...
    def handle_request(self):   # 请求处理函数
        environ = {             # 请求相关变量
            "wsgi.input": self.stdin  # request内容
            "wsgi.version": self.wsgi_version # wsgi版本信息
            ...
        }
        iterResult = self.app(environ, self.start_response)     # 业务逻辑处理请求,返回可迭代对象

        for data in iterResult:
            self.write(data)        # 将数据挨个发送到缓存区

        self.send_data()            # 将结果返回给客户端

对于application有以下要求:

  1. 必须是一个可调用对象,并且接收environ、start_response两个参数;environ为server端解析的当前请求环境变量;
  2. 返回值是一个可迭代对象

application的简单示例

def application(environ, start_response):    # 接收environ、start\_response

    start_response('200 OK', [('Content-Type', 'text/html')])    # 调用start\_response 用于设置响应状态和响应头部信息

    return [b'<h1>Hello, web!</h1>']    # 返回一个可迭代对象,作为响应内容

BestAIHub
3 声望1 粉丝