服務(wù)運(yùn)行
Django項(xiàng)目有兩種常見的運(yùn)行方法,第一種主要用于測(cè)試開發(fā)環(huán)境,通過runserver命令啟動(dòng),用Django自帶的web server運(yùn)行;另外一種主要用于正式生產(chǎn)環(huán)境,用gunicorn這樣的WSGI server部署運(yùn)行。
runserver的運(yùn)行方法
第一種情況,一般通過命令python manage.py runserver啟動(dòng),其中manage.py相關(guān)的代碼具體在文章django源碼分析之項(xiàng)目創(chuàng)建中已經(jīng)詳細(xì)描述,它的主要邏輯是根據(jù)用戶輸入來確定執(zhí)行哪個(gè)命令。
比如用戶輸入的服務(wù)啟動(dòng)命令python manage.py runserver,具體執(zhí)行的命令就是runserver,代碼位置在django/core/management/commands/runserver.py。
runserver中執(zhí)行過程如下:
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):
# 獲取服務(wù)器地址
server_address = (addr, port)
if threading:
httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
else:
httpd_cls = server_cls
# 創(chuàng)建一個(gè)socket server作為web服務(wù)器的作用,去監(jiān)聽端口
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
# 設(shè)置wsgi程序
httpd.set_app(wsgi_handler)
httpd.serve_forever()
上面的wsgi_handler是一個(gè)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))
# 啟動(dòng)request_started信號(hào)事件
signals.request_started.send(sender=self.__class__, environ=environ)
# 對(duì)environ進(jìn)行進(jìn)一步處理,使之成為在Django的view中的request參數(shù)
request = self.request_class(environ)
# 調(diào)用了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部署的運(yùn)行方法
WSGI是Web Server Gateway Interface的縮寫。以層的角度來看,WSGI所在層的位置低于CGI。但與CGI不同的是WSGI具有很強(qiáng)的伸縮性且能運(yùn)行于多線程或多進(jìn)程的環(huán)境下,這是因?yàn)閃SGI只是一份標(biāo)準(zhǔn)并沒有定義如何去實(shí)現(xiàn)。實(shí)際上WSGI并非CGI,因?yàn)槠湮挥趙eb應(yīng)用程序與web服務(wù)器之間,而web服務(wù)器可以是CGI,mod_python(注:現(xiàn)通常使用mod_wsgi代替),F(xiàn)astCGI或者是一個(gè)定義了WSGI標(biāo)準(zhǔn)的web服務(wù)器就像python標(biāo)準(zhǔn)庫(kù)提供的獨(dú)立WSGI服務(wù)器稱為wsgiref。
正常環(huán)境的部署方式,一遍通過WSGI server的配置文件直接指向項(xiàng)目的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()
后續(xù)流程和runserver的基本一致