Django WSGI 初探
起步
在第一章说到,django 使用 WSGIServer 作为内置服务器软件,这个类的实现在 django/core/servers/basehttp.py 文件中定义,这个类继承自 wsgiref.simple_server.WSGIServer 。django中自带的各种 ServerHandler , WSGIServer , WSGIRequestHandler 都基于自python模块 wsgiref 进行及其简单的封装而成的。
Django 的内置服务器
Django 内置服务器在 django.core.servers 和 django.core.handlers, 这两者共同来实现。它们基本都是基于 wsgiref.simple_server 继承过来的,关于python本身的标准库中的模块我们就不分析了,这个模块里大致就是从文本级别的解析http包。 从 django.core.servers.basehttp 中:
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
server_address = (addr, port)
if threading:
httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
else:
httpd_cls = WSGIServer
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
if threading:
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever() # 长期运行
这里的 wsgi_handler 变量是一个 StaticFilesHandler 实例(下文提到)。
WSGI 应用
作为第一个作为wsgi应用,它的定义是在 settings.py 中有个项:
WSGI_APPLICATION = 'webui.wsgi.application'
打开其同目录下的 wsgi.py :
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webui.settings")
application = get_wsgi_application()
get_wsgi_application() 中实例化了 django.core.handlers.wsgi.WSGIHandler, 并无其他操作。wsgi通过 ServerHandler 来执行django的应用程序,第一个落地对象是 StaticFilesHandler ,从 runserver 的命令执行器 django.contrib.staticfiles.management.commands.runserver 可以得到:
class Command(RunserverCommand):
...
def get_handler(self, *args, **options):
handler = super(Command, self).get_handler(*args, **options) # handle 即上述中 WSGIHandler 的实例
use_static_handler = options['use_static_handler']
insecure_serving = options['insecure_serving']
if use_static_handler and (settings.DEBUG or insecure_serving):
return StaticFilesHandler(handler)
return handler
简单看看 StaticFilesHandler 的构成:
class StaticFilesHandler(WSGIHandler):
def __init__(self, application):
self.application = application
self.base_url = urlparse(self.get_base_url())
super(StaticFilesHandler, self).__init__()
def _should_handle(self, path): # 是否是静态文件
return path.startswith(self.base_url[2]) and not self.base_url[1]
def __call__(self, environ, start_response):
if not self._should_handle(get_path_info(environ)):# 如果不是静态文件,交给wsgi应用处理
return self.application(environ, start_response)
return super(StaticFilesHandler, self).__call__(environ, start_response)
StaticFilesHandler 的作用是当请求出现时,先检查url是不是一个静态文件请求,如果是的话则进入静态文件(图片、css样式文件、js脚本文件等等)处理的view,如果不是的话则将该请求提交给Django的handler来进行处理(解析url、执行对应的view代码块、渲染和返回template)。
当请求不是静态文件时候,就调用 self.application(environ, start_response) ,也就是 django.core.handlers.wsgi.WSGIHandler 中定义的 __call__ 方法:
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __call__(self, environ, start_response):
try:
# 实例化 WSGIRequest
request = self.request_class(environ)
except UnicodeDecodeError:
response = http.HttpResponseBadRequest()
else:
# 调用 self.get_response(), 将会返回一个相应对象 response
response = self.get_response(request)
response._handler_class = self.__class__ # 将 self 挂钩到 response 对象
status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
start_response(force_str(status), response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
response = environ['wsgi.file_wrapper'](response.file_to_stream)
return response
这个 __call__ 中主要做了两件事,一个是根据字典 environ 实例化了一个 WSGIRequest 对象 request = self.request_class(environ) ,这个也就是开发django中,view视图中作为参数的那个 request。这个对象是根据wsgi接口中的WSGIRequestHandler中的 get_environ() 方法做的工作,针对 environ 进行预处理(例如header、PATH_INFO、REQUEST_METHOD、charset等等。
第二件事是获得 reponse 对象 self.get_response(request) ,有意思的是,在其父类的 get_response 中,通过中间件的机制,执行的可能是 django.contrib.staticfiles.StaticFilesHandler , 也可能是 django.core.handlers.wsgi.WSGIHandler 等。

浙公网安备 33010602011771号