• WSGI原理与简单实现


    WSGI指定需要由Web应用程序端和Web服务器端实现的规则,以便它们可以彼此交互。因此,符合WSGI的服务器将能够与符合WSGI的Web应用程序进行通信。

    在WSGI架构中,WSGI应用程序必须是可调用的,并且必须被提供给Web服务器,因此,只要服务器收到请求,Web服务器就可以调用Web应用程序。


    实现一个符合WSGI的应用程序

    • Server/Gateway Side:这里使用参考库wsgiref提供的WSGI Server作为服务器

    • Application/Framework Side:创建一个函数作为可调用对象作为web应用程序


    from wsgiref.simple_server import make_server
    
    def app(environ, start_response):
        path = environ.get('PATH_INFO')
        if path == '/':
            response_body = "<h1>Hello, world</h1>"
        else:
            response_body = "<h1>nothing</h1>"
    
        start_response("200 OK", [('Content-Type','text/html; charset=utf-8')])
        return [response_body.encode()]
    
    httpd = make_server('127.0.0.1', 5000, app)
    
    try:
        print('server start in http://127.0.0.1:5000')
        httpd.serve_forever()
    except Exception as e:
        print(e)
    except KeyboardInterrupt:
        print('server stop...')
        httpd.server_close()
    

    • 服务器将传入两个参数来调用应用程序。因此,它必须接受两个参数。这是application符合WSGI的条件之一

    • 传递给它的第一个参数将是一个变量,其中包含有关请求的各种信息。在示例中,我们使用它来读取请求路径,如果路径名是/则返回Hello, world,否则返回nothing。

    • 传递给它的第二个参数将是可调用的。application必须使用此可调用对象来通知服务器响应状态并设置各种标头。这是application符合WSGI的第二个条件

    • 最后返回的必须是一个已经encode了的可迭代对象,响应被application返回到WSGI服务器。

    • 服务器最终将此响应传回客户端。


    Application/Framework 的实现

    • 应用程序应该是一个可调用对象,Python中可以是函数、类、实现了__call__方法的类的实例

    • 这个可调用对象应该接收之前说的两个参数

    • 调用这个可调用对象后必须返回一个可迭代对象


    1、函数实现

    见上面的代码


    2、类实现(方法一)

    response_body = "Hello, world"
    
    class app:
        def __call__(self, environ, start_response):
            path = environ.get('PATH_INFO')
            if path == '/':
                response_body = "<h1>Hello, world</h1>"
            else:
                response_body = "<h1>nothing</h1>"
            start_response("200 OK", [('Content-Type','text/html; charset=utf-8')])
            return [response_body.encode()]
    
    httpd = make_server('127.0.0.1', 5000, app())
    
    try:
        print('server start in http://127.0.0.1:5000')
        httpd.serve_forever()
    except Exception as e:
        print(e)
    except KeyboardInterrupt:
        print('server stop...')
        httpd.server_close()
    

    3、类实现(方法二)

    response_body = "Hello, world"
    
    class app:
        def __init__(self, environ, start_response):
            path = environ.get('PATH_INFO')
            if path == '/':
                response_body = "<h1>Hello, world</h1>"
            else:
                response_body = "<h1>nothing</h1>"
            start_response("200 OK", [('Content-Type','text/html; charset=utf-8')])
            self.res = [response_body.encode()]
    
        def __iter__(self):
            yield from self.res
    
    httpd = make_server('127.0.0.1', 5000, app)
    
    try:
        print('server start in http://127.0.0.1:5000')
        httpd.serve_forever()
    except Exception as e:
        print(e)
    except KeyboardInterrupt:
        print('server stop...')
        httpd.server_close()
    

    关于environ

    environ字典包含了一些CGI规范要求的数据,以及WSGI规范新增的数据,还可能包含一些操作系统的环境变量以及Web服务器相关的环境变量,具体见environ

    首先是CGI规范中要求的变量:


    参数 说明
    REQUEST_METHOD HTTP请求方法,'GET', 'POST'等,不能为空
    SCRIPT_NAME HTTP请求path中的初始部分,用来确定对应哪一个application,当application对应于服务器的根,可以为空
    PATH_INFO path中剩余的部分,application要处理的部分,可以为空
    QUERY_STRING HTTP请求中的查询字符串,URL中?后面的内容
    CONTENT_TYPE HTTP headers中的Content-Type内容
    CONTENT_LENGTH HTTP headers中的Content-Length内容
    SERVER_NAME
    SERVER_PORT
    服务器域名和端口,这两个值和前面的SCRIPT_NAME, PATH_INFO拼起来可以得到完整的URL路径
    SERVER_PROTOCOL HTTP协议版本,'HTTP/1.0'或'HTTP/1.1'
    HTTP_Variables 和HTTP请求中的headers对应,比如'User-Agent'写成'HTTP_USER_AGENT'的格式

    WSGI规范中还要求environ包含下列成员:


    参数 说明
    wsgi.version 一个元组(1, 0),表示WSGI版本1.0
    wsgi.url_scheme http或者https
    wsgi.input 一个类文件的输入流,application可以通过这个获取HTTP请求的body
    wsgi.errors 一个输出流,当应用程序出错时,可以将错误信息写入这里
    wsgi.multithread 当application对象可能被多个线程同时调用时,这个值需要为True
    wsgi.multiprocess 当application对象可能被多个进程同时调用时,这个值需要为True
    wsgi.run_once 当server期望application对象在进程的生命周期内只被调用一次时,该值为True

    关于start_resposne

    start_response是一个可调用对象,接收两个必选参数和一个可选参数:

    • status: 一个字符串,表示HTTP响应状态字符串,比如'200 OK'、'404 Not Found'

    • headers: 一个列表,包含有如下形式的元组:(header_name, header_value),用来表示HTTP响应的headers

    • exc_info(可选): 用于出错时,server需要返回给浏览器的信息

    start_response必须返回一个write(body_data)。我们知道HTTP的响应需要包含status,headers和body,所以在application对象将body作为返回值return之前,需要先调用start_response,将status和headers的内容返回给server,这同时也是告诉server,application对象要开始返回body了。


    参考

  • 相关阅读:
    ghm一般规则
    沃尔玛强推RFID内外交困:供应商阳奉阴违
    电子商务物流解决方案
    database url
    物流中新技术应用的必要性
    美国物流管理协会更名标志全球物流进入供应链时代
    业内专家激辩物流挑战与机遇
    问的智慧
    调查报告:2003年物流信息化现状及挑战
    查找在菜单里提交的报表所在职责
  • 原文地址:https://www.cnblogs.com/bqzzz/p/14471618.html
Copyright © 2020-2023  润新知