• [TimLinux] django WSGI入口分析及自定义WSGIHandler思路


    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技术来实现线程安全的请求变量赋值。
  • 相关阅读:
    探索Javascript 异步编程
    前端性能调优
    怎样选择前端框架
    前端地图截屏方案
    不一样的山顶角
    前后端分离场景下的另类登录认证方案
    React Diff 算法
    纯css实现Magicline Navigation(下划线动画导航菜单)
    Tinymce group plugin
    自适应process组件
  • 原文地址:https://www.cnblogs.com/timlinux/p/9354716.html
Copyright © 2020-2023  润新知