以線上版本中Django和Nginx、uwsgi搭配,這里首先要了解uWSGI、uwsgi、WSGI分別代表着什么,其中uWSGI實現了uwsgi、WSGI、HTTP協議的Web服務器,WSGI是通信協議,而uwsgi則是線路協議。

當用戶啟動Nginx以后,Nginx會直接處理靜態資源請求,動態資源請求則轉發給uWSGI服務器。
調用get_wsgi_application創建WSGIHandler對象
Web應用啟動以后,在settings.py
中會調用該字段項WSGI_APPLICATION
,這個字段項指向的是項目的wsgi.py
文件,在這個文件中,調用了get_wsgi_application()
創建了application,如下:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Sparrow.settings")
application = get_wsgi_application()
接下來再看get_wsgi_application
的具體實現:
import django
from django.core.handlers.wsgi import WSGIHandler
def get_wsgi_application():
"""
The public interface to Django's WSGI support. Should return a WSGI
callable.
Allows us to avoid making django.core.handlers.WSGIHandler public API, in
case the internal WSGI implementation changes or moves in the future.
"""
django.setup(set_prefix=False)
return WSGIHandler()
里面調用了setup
函數完成了一下動作:
- 初始化app配置和加載app模塊;
- 加載model模塊;
- 運行app配置的開始函數;
同時返回了WSGIHandler
對象,這個對象繼承自BaseHandler
對象,在WSGIHandler初始化的時候還調用了BaseHandler對象的load_middleware()
方法來加載中間件,也就是在settings.py中的MIDDLEWARE
包含的所有中間件;注意,這里只有在初始化的時候調用,也就是只會加載一次即可。
在BaseHandler
中,分別用多個數組保存對應的中間件的回調函數,分別是:
- _request_middleware
- _view_middleware
- _template_response_middleware
- _response_middleware
- _exception_middleware
在加載的時候,則會根據給定的類創建對應的中間件,判斷中間件是否有對應的函數,有則將該函數加入到對應的數組中,如下:
def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWARE (or the deprecated
MIDDLEWARE_CLASSES).
Must be called after the environment is fixed (see __call__ in subclasses).
"""
self._request_middleware = [] # 處理請求
self._view_middleware = [] # 處理視圖
self._template_response_middleware = [] # 處理響應的模版內容
self._response_middleware = [] # 處理響應
self._exception_middleware = [] # 處理錯誤
# 處理廢棄版本
if settings.MIDDLEWARE is None:
warnings.warn(
"Old-style middleware using settings.MIDDLEWARE_CLASSES is "
"deprecated. Update your middleware and use settings.MIDDLEWARE "
"instead.", RemovedInDjango20Warning
)
handler = convert_exception_to_response(self._legacy_get_response)
for middleware_path in settings.MIDDLEWARE_CLASSES:
mw_class = import_string(middleware_path)
try:
mw_instance = mw_class()
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
else:
logger.debug('MiddlewareNotUsed: %r', middleware_path)
continue
if hasattr(mw_instance, 'process_request'):
self._request_middleware.append(mw_instance.process_request)
if hasattr(mw_instance, 'process_view'):
self._view_middleware.append(mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.insert(0, mw_instance.process_template_response)
if hasattr(mw_instance, 'process_response'):
self._response_middleware.insert(0, mw_instance.process_response)
if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.insert(0, mw_instance.process_exception)
else: # 處理新版本
handler = convert_exception_to_response(self._get_response)
for middleware_path in reversed(settings.MIDDLEWARE):
middleware = import_string(middleware_path)
try:
mw_instance = middleware(handler)
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
else:
logger.debug('MiddlewareNotUsed: %r', middleware_path)
continue
if mw_instance is None:
raise ImproperlyConfigured(
'Middleware factory %s returned None.' % middleware_path
)
# 注意,加入的是對象的函數
if hasattr(mw_instance, 'process_view'):
self._view_middleware.insert(0, mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.append(mw_instance.process_template_response)
if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.append(mw_instance.process_exception)
handler = convert_exception_to_response(mw_instance)
# We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
self._middleware_chain = handler
在WSGIHander
初始化完成之后,然后它給調度程序發送一個信號request_started
,並且將environ
作為參數一塊傳遞過去;同時還構造WSGIRequest
請求對象,因為其繼承的是HttpRequest
,所以里面封裝了HTTP協議的內容,比如meta、cookie、content_type等等;如下:
request_class = WSGIRequest
request = self.request_class(environ)
接下來根據前面構造好的request作為參數通過get_response
方法,在這個方法中會遍歷_response_middleware
數組中的每個方法並且獲取到相應的響應信息,在這里對這些響應信息進行封裝,設置一些cookie、headers等等;如下:
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ) # 表明開始請求
request = self.request_class(environ)
response = self.get_response(request) # 獲取響應
response._handler_class = self.__class__
status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
start_response(force_str(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
URLConf通過url.py文件找到請求的URL對應的視圖函數
如果view不是一個函數,那么說明下面還有多個url,這種就是使用了include
的情況,那么則會實例化RegexURLResolver
對象,遞歸的往下找;相反,如果是一個函數,那么則會實例化RegexURLPattern
對象,當url匹配到這個正則表達式的時候,就會進入到相應的函數。如下:
def url(regex, view, kwargs=None, name=None):
if isinstance(view, (list, tuple)):
# For include(...) processing.
urlconf_module, app_name, namespace = view
return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
elif callable(view):
return RegexURLPattern(regex, view, kwargs, name)
else:
raise TypeError('view must be a callable or a list/tuple in the case of include().')
View Middlewares被訪問,它同樣可以對request做一些處理或者直接返回response
一旦知道了視圖函數和相關的參數,處理器就會查看它的 _view_middleware 列表,並調用其中的方法。
在view中執行相關的邏輯,可以選擇性的通過Models訪問底層的數據。如果需要的話,Views可以創建一個額外的Context,Context被當做變量傳給Template,比如將Models中獲取的數據作為Context變量傳遞給模版。
模版根據可能傳遞過來的信息填充到指定的位置,開始進行渲染,渲染后的內容返回給View。
Response Middlewares處理Response
在Response生成之前,會執行Response Middlewares的邏輯。
當一個模版完成渲染,或者產生了其它合適的輸出,View就會產生一 個 django.http.HttpResponse 實例,然后設置一些Headers、Cookies等等。
一旦 middleware完成了最后環節,處理器將發送一個信號 request_finished,訂閱這個信號的事件會清空並釋放任何使用中的資源。
上面的情況並沒有考慮到錯誤的情況,如果出錯執行 exception middleware 相關邏輯,會有信號got_request_exception
進行通知,如下:
except Exception: # Any exception should be gathered and handled
signals.got_request_exception.send(sender=self.__class__, request=request)
response = self.handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
參考文章:
Django的一次請求到響應的流程