初步理解Python Web WSGI

首先先来了解一下:

WSGI 概念

Web是怎么工作的?

  • 浏览器访问url,发送一个HTTP请求。
  • 服务器收到请求后生成HTML文档,并把这个文档作为HTTP响应中的Body给浏览器。
  • 浏览器解析HTTP响应中的Body生成展示页面。

但是如果要动态生成HTML,则需要一个专用的web服务器,所以一旦一个框架选择了某个web服务器,基本上就不太好更改了,所以定义一个统一的接口极为重要,这就是WSGI接口


一个简单的符合WSGI规范的函数:

from wsgiref.simple_server import make_server

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ['<h1>Hello %s</h1>' % (environ['PATH_INFO'][1:] or 'Web')]

httpd = make_server('127.0.0.1', 8000, application)
print "Serving HTTP on port 8000..."
httpd.serve_forever()

Python内置了一个纯Python编写的测试用的WSGI服务器,wsgiref模块。

application 是符合WSGI规范的一个函数,其中两个参数的作用:

  • environ 是一个dict对象,包含了浏览器的所有请求信息。
  • start_response 发送HTTP响应的函数。

start_response 函数接受两个参数,第一个为HTTP响应码。第二个为两元组组成的列表,用于表示响应头。
return 中的值作为Body响应给客户端。

打开浏览器输入 127.0.0.1:8000 将会显示:

这里写图片描述

更多WSGI的介绍,查阅 PEP 333

使用werkzeug创建一个WSGI应用

from werkzeug.wrappers import Request, Response 
from werkzeug.serving import run_simple 

class Fish(object): 
    def __init__(self, package_name): 
        self.package_name = package_name 
        self.debug = False 

    def dispatch_request(self, request, environ): 
        return Response('Hello \n%s!\n%s' % (environ or "World", request)) 

    def run(self, host="127.0.0.1", port=8000, **options): 
        if 'debug' in options: 
            self.debug = options.pop('debug') 
        options.setdefault('use_reloader', self.debug) 
        options.setdefault('use_debugger', self.debug) 
        return run_simple(host, port, self, **options) 

    def wsgi_app(self, environ, start_response): 
        request = Request(environ) 
        #start_response('200 OK', [('Content-Type', 'text/html')]) 
        response = self.dispatch_request(request, environ) 
        return response(environ, start_response) 

    def __call__(self, environ, start_response): 
        return self.wsgi_app(environ, start_response) 

def create_app(package_name=None): 
    app = Fish(package_name) 
    return app 

if __name__ == '__main__': 
    app = Fish(__name__) 
    app.run(debug=True) 

WSGIServer

好了,上面的例子告诉我们 werkzeug WSGI服务器运行的基础就是werkzeug.serving 当中 run_simple 函数,然后我们顺着它找,发现最终 run_simple() 返回的是一个 *WSGIServer 的实例,然后调用其 serve_forever() 方法,werkzeug中定义了不少WSGIServer的类,有多线程的,有fork进程的,我们暂时分析 servering.py 中一个名为 BaseWSGIServer 的类。

来看一下 BaseWSGIServer 的源码:

try:
    from SocketServer import ThreadingMixIn, ForkingMixIn
    from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
except ImportError:
    from socketserver import ThreadingMixIn, ForkingMixIn
    from http.server import HTTPServer, BaseHTTPRequestHandler

class BaseWSGIServer(HTTPServer, object):
    """Simple single-threaded, single-process WSGI server."""
    multithread = False
    multiprocess = False
    request_queue_size = 128

    def __init__(self, host, port, app, handler=None,
                 passthrough_errors=False, ssl_context=None):
        if handler is None:
            handler = WSGIRequestHandler
        self.address_family = select_ip_version(host, port)
        HTTPServer.__init__(self, (host, int(port)), handler)
        self.app = app
        self.passthrough_errors = passthrough_errors
        self.shutdown_signal = False

        if ssl_context is not None:
            if isinstance(ssl_context, tuple):
                ssl_context = load_ssl_context(*ssl_context)
            if ssl_context == 'adhoc':
                ssl_context = generate_adhoc_ssl_context()
            self.socket = ssl_context.wrap_socket(self.socket,
                                                  server_side=True)
            self.ssl_context = ssl_context
        else:
            self.ssl_context = None

    def log(self, type, message, *args):
        _log(type, message, *args)

    def serve_forever(self):
        self.shutdown_signal = False
        try:
            HTTPServer.serve_forever(self)
        except KeyboardInterrupt:
            pass
        finally:
            self.server_close()

    def handle_error(self, request, client_address):
        if self.passthrough_errors:
            raise
        else:
            return HTTPServer.handle_error(self, request, client_address)

    def get_request(self):
        con, info = self.socket.accept()
        return con, info

源码很简单,其实也就是继承了标准库 BaseHTTPServer.HTTPServer ,然后重写了一些方法而已。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值