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

Python WSGI协议中文版

程序员文章站 2022-03-04 10:40:50
...

本文引用自github某大牛的分享

Python基础学完后,免不了要深入到Python的主流Web框架(Python科学计算那部分暂时用不到可以先不管),在学习Flask这些框架的过程中发现它们的底层都是WSGI协议,故决定先啃下WSGI,鉴于目前网上几乎没有(完整的)WSGI中文版,于是大牛干脆自己翻译,这样也有助于加深大牛自己的理解,同时也能够帮助到一些初学者。

PEP 333 - Python Web Server Gateway Interface v1.0 中文版

服务器/网关 端
每一次,当HTTP客户端冲着应用程序发来一个请求,服务器/网关都会调用应用程序可调用者(callable)。为了阐述方便,这里有一个CGI网关,简单的说它就是一个以应用程序对象为参数的函数实现,注意,本例中对错误只做了有限的处理,因为默认情况下没有被捕获到的异常都会被输出到sys.stderr并被服务器记录下来。

import os, sys

def run_with_cgi(application):

    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

    if environ.get('HTTPS', 'off') in ('on', '1'):
        environ['wsgi.url_scheme'] = 'https'
    else:
        environ['wsgi.url_scheme'] = 'http'

    headers_set = []
    headers_sent = []

    def write(data):
        if not headers_set:
             raise AssertionError("write() before start_response()")

        elif not headers_sent:
             # 在第一次输出之前发送已存储的报头。
             status, response_headers = headers_sent[:] = headers_set
             sys.stdout.write('Status: %s\r\n' % status)
             for header in response_headers:
                 sys.stdout.write('%s: %s\r\n' % header)
             sys.stdout.write('\r\n')

        sys.stdout.write(data)
        sys.stdout.flush()

    def start_response(status, response_headers, exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    # 如果报头已发送,则重新抛出原始的异常。
                    raise exc_info[0], exc_info[1], exc_info[2]
            finally:
                exc_info = None     # 避免死循环。
        elif headers_set:
            raise AssertionError("Headers already set!")

        headers_set[:] = [status, response_headers]
        return write

    result = application(environ, start_response)
    try:
        for data in result:
            if data:    # 在报文体出现前不发送报头。
                write(data)
        if not headers_sent:
            write('')   # 如果报文体为空,则发送报头。
    finally:
        if hasattr(result, 'close'):
            result.close()