Python自学笔记十一、WSGI

来源:互联网 发布:深圳阿里云幕布拍照 编辑:程序博客网 时间:2024/06/06 04:53

PEP 0333 – Python Web Server Gateway Interface 是一种 web server or gateway 和 python web application or framework 之间简单通用的接口,符合这种接口的 application 可运行在所有符合该接口的 server 上。通俗的讲,WSGI 规范了一种简z单的接口,解耦了 server 和 application,使得双边的开发者更加专注自身特性的开发。
Web server/gateway: 即 HTTP Server,处理 HTTP 协议,接受用户 HTTP 请求和提供并发,调用 web application 处理业务逻辑。通常采用 C/C++ 编写,代表:apache, nginx 和 IIS。
Python Web application/framework: 专注业务逻辑的 python 应用或者框架。

这里写图片描述

The Application/Framework Side

Application/framework 端必须定义一个 callable object,callable object 可以是以下三者之一:

function, method
class
instance with a __call__ method
Callable object 必须满足以下两个条件:

接受两个参数:字典(environ),回调函数(start_response,返回 HTTP status,headers 给 web server)
返回一个可迭代的值
基于 callable function 的 application/framework 样例如下:

def application(environ, start_response):    start_response('200 OK', [('Content-Type', 'text/plain')])    return ['This is a python application!']

基于 callable class 的 application/framework 样例如下:

class ApplicationClass(object):    def __init__(self, environ, start_response):        self.environ = environ        self.start_response = start_response    def __iter__(self):        self.start_response('200 OK', [('Content-type', 'text/plain')])        yield "Hello world!n"

The Server/Gateway Side
Server/gateway 端主要专注 HTTP 层面的业务,重点是接收 HTTP 请求和提供并发。每当收到 HTTP 请求,server/gateway 必须调用 callable object:

接收 HTTP 请求,但是不关心 HTTP url, HTTP method 等
为 environ 提供必要的参数,实现一个回调函数 start_response,并传给 callable object
调用 callable object
我们直接使用支持 WSGI 框架的 wsgiref 库,编写一个样例:

# application/framework sidedef application(environ, start_response):    start_response('200 OK', [('Content-Type', 'text/plain')])    return ['This is a python application!']# server/gateway sideif __name__ == '__main__':    from wsgiref.simple_server import make_server    server = make_server('0.0.0.0', 8080, application)    server.serve_forever()

运行后,对于任意的 url 和 method,本例的返回值均为 ‘This is a python application!’

$curl 127.0.0.1:8080This is a python application!                                                                                                                                                                                                                                                  $ curl 127.0.0.1:8080/testThis is a python application!

Middleware: Components that Play Both Sides
这里写图片描述
Middleware 处于 server/gateway 和 application/framework 之间,对 server/gateway 来说,它相当于 application/framework;对 application/framework 来说,它相当于 server/gateway。每个 middleware 实现不同的功能,我们通常根据需求选择相应的 middleware 并组合起来,实现所需的功能。比如,可在 middleware 中实现以下功能:

1.根据 url 把用户请求调度到不同的 application 中。
2.负载均衡,转发用户请求
3.预处理 XSL 等相关数据
44限制请求速率,设置白名单

这里写图片描述

本例实现了一个 IPBlacklist 的 middleware:

class IPBlacklistMiddleware(object):    def __init__(self, app):        self.app = app    def __call__(self, environ, start_response):        ip_addr = environ.get('HTTP_HOST').split(':')[0]        if ip_addr not in ('127.0.0.1'):            return forbidden(start_response)        return self.app(environ, start_response)def forbidden(start_response):    start_response('403 Forbidden', [('Content-Type', 'text/plain')])    return ['Forbidden']def application(environ, start_response):    start_response('200 OK', [('Content-Type', 'text/plain')])    return ['This is a python application!']if __name__ == '__main__':    from wsgiref.simple_server import make_server    application = IPBlacklistMiddleware(application)    server = make_server('0.0.0.0', 8080, application)    server.serve_forever()
# 从本机测试$ curl 127.0.0.1:8080/testThis is a python application!# 从其它主机测测试                                                                                                                                                                                                 $ curl 10.10.10.2:8080/test                                                                                                                                                                                                                                    Forbidden

Path Dispatching

至此样例的一个不足之处是对于任意的 url 和 method,程序的返回值均为 ‘This is a python application!’,所以我们需要增加 path dispatch 功能。由于 WSGI 框架下的 server/gateway 不处理 url 和 method,所以 url mapping 需由 application/framework 端完成。注意到参数 environ,它包含以下变量:

1.REQUEST_METHOD: 即 HTTP method
2.PATH_INFO: 即 HTTP url

所以 application/framework 可以根据 environ 的 REQUEST_METHOD 和 PATH_INFO 实现 path dispatch,样例如下:

class IPBlacklistMiddleware(object):    def __init__(self, app):        self.app = app    def __call__(self, environ, start_response):        ip_addr = environ.get('HTTP_HOST').split(':')[0]        if ip_addr not in ('127.0.0.1'):            return forbidden(start_response)        return self.app(environ, start_response)def dog(start_response):    start_response('200 OK', [('Content-Type', 'text/plain')])    return ['This is dog!']def cat(start_response):    start_response('200 OK', [('Content-Type', 'text/plain')])    return ['This is cat!']def not_found(start_response):    start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])    return ['Not Found']def forbidden(start_response):    start_response('403 Forbidden', [('Content-Type', 'text/plain')])    return ['Forbidden']def application(environ, start_response):    path = environ.get('PATH_INFO', '').lstrip('/')    mapping = {'dog': dog, 'cat': cat}    call_back = mapping[path] if path in mapping else not_found    return call_back(start_response)if __name__ == '__main__':    from wsgiref.simple_server import make_server    application = IPBlacklistMiddleware(application)    server = make_server('0.0.0.0', 8080, application)    server.serve_forever()
0 0
原创粉丝点击