django源码分析之服务启动

服务运行

Django项目有两种常见的运行方法,第一种主要用于测试开发环境,通过runserver命令启动,用Django自带的web server运行;另外一种主要用于正式生产环境,用gunicorn这样的WSGI server部署运行。

runserver的运行方法

第一种情况,一般通过命令python manage.py runserver启动,其中manage.py相关的代码具体在文章django源码分析之项目创建中已经详细描述,它的主要逻辑是根据用户输入来确定执行哪个命令。
比如用户输入的服务启动命令python manage.py runserver,具体执行的命令就是runserver,代码位置在django/core/management/commands/runserver.py
runserver中执行过程如下:

handle() -> run() -> inner_run() -> django.core.servers.basehttp.run()

其中django.core.servers.basehttp.run()django/core/servers/basehttp.py

def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
    # 获取服务器地址
    server_address = (addr, port)
    if threading:
        httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
    else:
        httpd_cls = server_cls
    # 创建一个socket server作为web服务器的作用,去监听端口
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
    if threading:
        # ThreadingMixIn.daemon_threads indicates how threads will behave on an
        # abrupt shutdown; like quitting the server by the user or restarting
        # by the auto-reloader. True means the server will not wait for thread
        # termination before it quits. This will make auto-reloader faster
        # and will prevent the need to kill the server manually if a thread
        # isn't terminating correctly.
        httpd.daemon_threads = True
    # 设置wsgi程序
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

上面的wsgi_handler是一个wsgi程序,在runserver中传入

  def get_handler(self, *args, **options):
        """Return the default WSGI handler for the runner."""
        return get_internal_wsgi_application()

其中django.core.servers.basehttp.get_internal_wsgi_application最后返回django.core.handlers.wsgi.WSGIHandler,在文件django/core/handlers/wsgi.py

class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.load_middleware()

    def __call__(self, environ, start_response):
        # 从environ中获取脚本目录前缀
        set_script_prefix(get_script_name(environ))
        # 启动request_started信号事件
        signals.request_started.send(sender=self.__class__, environ=environ)
        # 对environ进行进一步处理,使之成为在Django的view中的request参数
        request = self.request_class(environ)
        # 调用了BaseHandler中的self._get_response方法。
        response = self.get_response(request)

        response._handler_class = self.__class__
        # 返回response
        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = list(response.items())
        for c in response.cookies.values():
            response_headers.append(('Set-Cookie', c.output(header='')))
        start_response(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

通过WSGI server部署的运行方法

WSGI是Web Server Gateway Interface的缩写。以层的角度来看,WSGI所在层的位置低于CGI。但与CGI不同的是WSGI具有很强的伸缩性且能运行于多线程或多进程的环境下,这是因为WSGI只是一份标准并没有定义如何去实现。实际上WSGI并非CGI,因为其位于web应用程序与web服务器之间,而web服务器可以是CGI,mod_python(注:现通常使用mod_wsgi代替),FastCGI或者是一个定义了WSGI标准的web服务器就像python标准库提供的独立WSGI服务器称为wsgiref。

正常环境的部署方式,一遍通过WSGI server的配置文件直接指向项目的demo_project/wsgi.py文件

"""
WSGI config for demo_project project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo_project.settings")

application = get_wsgi_application()

后续流程和runserver的基本一致