欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python wsgi

程序员文章站 2022-06-06 18:33:58
...

wsgi是什么

  • wsgi(Web Server Gateway Interface)web服务器网关接口,是一套在httpserver(比如nginx,apache)和python程序之间传递的接口标准,WSGI 是基于现存的 CGI 标准而设计的.
  • wsgi在PEP333中定义
  • WSGI 的设计参考了 Java 的 servlet
  • python 中,作为wsgi服务器的组件有uwsgi,gunicorn等。
  • 常见的http请求的处理流程如下所示:

Nginx-->(wsgi)gunicorn-->framework-->application
wsgi工作在wsgi服务器和web服务器的中间,一般是使用nginx来进行反向代理。然后使用gunicorn来当wsgi服务器。
其中,nginx一般用作负载均衡处理,gunicorn用于http请求的解析和封装,为framework提供梳理好的http数据。而application则用于根据框架请求的数据进行相应的处理。

wsgi的规范:

  1. wsgi规定每个 python 程序(Application)必须是一个可调用的对象(实现了_call_ 函数的方法或者类),接受两个参数 environ(WSGI 的环境信息) 和 start_response(开始响应请求的函数),并且返回 iterable
    其中:
    - environ 和 start_response 由 http server 提供并实现
    - environ 变量是包含了环境信息的字典
    - Application 内部在返回前调用 start_response
    - start_response也是一个 callable,接受两个必须的参数,status(HTTP状态)和 response_headers(响应消息的头)
    - 可调用对象要返回一个值,这个值是可迭代的。
    2:

wsgi实现:

wsgi 应用端实现:

# 1. 可调用对象是一个函数
def application(environ, start_response):

   response_body = 'The request method was %s' % environ['REQUEST_METHOD']

   # HTTP response code and message
   status = '200 OK'

   # 应答的头部是一个列表,每对键值都必须是一个 tuple。
   response_headers = [('Content-Type', 'text/plain'),
                       ('Content-Length', str(len(response_body)))]

   # 调用服务器程序提供的 start_response,填入两个参数
   start_response(status, response_headers)

   # 返回必须是 iterable
   return [response_body]    

# 2. 可调用对象是一个类
class AppClass:
    """这里的可调用对象就是 AppClass 这个类,调用它就能生成可以迭代的结果。
        使用方法类似于: 
        for result in AppClass(env, start_response):
             do_somthing(result)
    """

    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        self.start(status, response_headers)
        yield "Hello world!\n"

# 3. 可调用对象是一个实例 
class AppClass:
    """这里的可调用对象就是 AppClass 的实例,使用方法类似于: 
        app = AppClass()
        for result in app(environ, start_response):
             do_somthing(result)
    """

    def __init__(self):
        pass

    def __call__(self, environ, start_response):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        self.start(status, response_headers)
        yield "Hello world!\n"

wsig是处于web server 和web application中间的一层,所以
wsgi server端实现:

import os, sys

def run_with_cgi(application):    # application 是程序端的可调用对象
    # 准备 environ 参数,这是一个字典,里面的内容是一次 HTTP 请求的环境变量
    environ = dict(os.environ.items())
    environ['wsgi.input']        = sys.stdin
    environ['wsgi.errors']       = sys.stderr
    environ['wsgi.version']      = (1, 0)
    environ['wsgi.multithread']  = False
    environ['wsgi.multiprocess'] = True
    environ['wsgi.run_once']     = True            
    environ['wsgi.url_scheme'] = 'http'

    headers_set = []
    headers_sent = []

    # 把应答的结果输出到终端
    def write(data):
        sys.stdout.write(data)
        sys.stdout.flush()

    # 实现 start_response 函数,根据程序端传过来的 status 和 response_headers 参数,
    # 设置状态和头部
    def start_response(status, response_headers, exc_info=None):
        headers_set[:] = [status, response_headers]
          return write

    # 调用客户端的可调用对象,把准备好的参数传递过去
    result = application(environ, start_response)

    # 处理得到的结果,这里简单地把结果输出到标准输出。
    try:
        for data in result:
            if data:    # don't send headers until body appears
                write(data)
    finally:
        if hasattr(result, 'close'):
            result.close()

参考连接:
wsgi PEP333翻译
WSGI协议的原理及实现