1. 命令行启动
命令行是通过runserver子命令来启动的,对应的django模块为django.core.management.commands.runserver,调用关系结构:
# 简化的运行代码: django.core.management.commands.runserver.py class Command: def get_handler(): return django.core.servers.basehttp.get_internal_wsgi_application() def run: # 命令行如果函数 self.run_inner() def run_inner(): handler = self.get_handler() django.core.servers.basehttp.run(..., handler, ...) django.core.servers.basehttp.py def get_internal_wsgi_application(): 1. settings.WSGI_APPLICAITON 2. 上面的配置不存在,则执行: django.core.wsgi.get_wsgi_application() def run(): 启动http服务,监听端口,注册WSGI django.core.wsgi.py def get_wsgi_application(): django.setup() return django.core.handlers.wsgi.WSGIHandler() django.core.handlers.wsgi.py class WSGIHandler(base.BaseHandler): def __init__(): self.load_middleware() # 装载了中间件 def __call__(self, environ, start_response): # 请求的入口函数 pass
2. web服务器启动
Web服务器配置: WSGIScriptAlias / /my/web/site/site/wsgi.py site/wsgi.py # 这个文件默认是与settings.py同级 import os from django.core.wsgi import get_wsgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE", 'site.settings') application = get_wsgi_applicaiton() application变量的获取与命令行最后部分是一致的。
3. 核心
这个核心函数的处理内容: django.core.wsgi.WSGIHandler.__call__(self, environ, start_response) 1. 发送一个信号 2. 处理请求、处理中间件 3. 处理响应 4. 调用start_response返回响应头 5. 返回响应体 __call__ 函数的特点: 1. 每次请求的入口函数 2. 这个函数内部代码都属于请求过程,也就是线程工作空间
4. 自定义 WSGI 思路
关键在于自定义 get_wsgi_applicaiton函数: 1. 根据代码,我认为可以在 settings 中配置 WSGI_APPLICATION 的方式来定义该函数,这个可能只能解决命令行启动问题 2. web服务器启动的时候,因为 site/wsgi.py 文件属于站点独立文件,我们其实可以自己重新这个文件的,这样很容易调用到自己定义的 get_wsgi_application() 函数 3. get_wsgi_applicaiton() 函数的返回值 设置为自己实现的 WSGIHandler() 就可以实现自己的 WSGI了。 4. 在 WSGIHandler 的 __call__ 方法内,定义一些全局变量,这个变量将属于整个线程,并且可以在各关联函数内使用,比如给
signals增加一个request 属性,则可以在所有 signal receiver函数内访问到这个属性了。 def __call__(...): setattr(signals, 'request', request)
5. 另外一种方法
这个方法的关键在于提供一个 middleware,然后在 middleware 的process_request 方法内,给一个公共模块设置属性的值,
这样这个属性的值在各模块内都是可访问的。 class MyMiddleware(MiddlewareMixin): def process_request(self, request): setattr(signals, 'request', request) def my(sender, **kwargs): if hasattr(signals, 'request'): print(singals.request) request_started.connect(my, sender=WSGIRequest)
这个方式不是线程安全的,signals对象属于进程变量,在所有现在内共享。可以考虑使用threading.local技术来实现线程安全的请求变量赋值。