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的基本一致