ミドルウェア、ソースコード解析
ミドルウェアの紹介
ミドルウェアはDjangoのフックが使用されているフレームレベルの要求と応答です。これは、グローバルにジャンゴの入力と出力を変化させるための軽量、低レベルのプラグインシステムです。各ミドルウェアコンポーネントは、いくつかの特定の機能を実行する責任があります。
注意して使用する必要があるので、その影響は、グローバルでのので、しかし、不適切な使用は、パフォーマンスに影響を与えることができます。
ミドルウェアは、ビュー機能が実行される前と後に、それは基本的にカスタムクラスである私たちが行っていくつかの追加作業を行うことができ、クラスは、特定の時点でこれらの要求を実行するためにいくつかの方法、Djangoフレームワークを定義します方法。
ミドルウェアは、入出力要求のフック処理を行うために、以下の5つの主要な機能で定義することができます。
- process一(自己、リクエスト)
- process_view(自己、リクエスト、view_func、view_argsと、view_kwargs)
- process_template_response(自己、リクエスト、レスポンス)
- process_exception(自己、リクエスト、例外)
- process_response(自己、リクエスト、レスポンス)
彼らの主な役割は、参照公式ドキュメントを。
これらの5つのフック関数は、次の図に見ることができるときにトリガします。
注:上記は、順序がミドルウェアの設定ファイルリスト内の順序で登録されていると述べました。
ソースコード解析
私は上記の順番を行いますミドルウェアに対処するにはどうすればよい、より多くの好奇心、そして私は、Djangoのソースで勉強に行きました。
まず、初期起動時には、WSGIを含む環境の設定、のDjangoの範囲は、初期化ミドルウェアコンポーネントを含むプロトコルを実装します。このエントリでミドルウェアの初期化関数を。
入力load_middleware
機能を、あなたは私たちが内部の5のリストに、ここにフック関数をカスタマイズすることができていることがわかります。そして、内部の設定を決定しMIDDLEWARE
た項目が空の場合、空の言葉が行くdjango.conf.global_settings.py
デフォルトの設定ファイル内にロードされ、中央でありますピースデフォルトのミドルウェア以下の2つだけ。
# django.conf.global_settings.py
MIDDLEWARE_CLASSES = [
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
]
MIDDLEWARE = None
上記のコードが行くように、我々は一般的に、プロジェクトの下で7つのデフォルトのミドルウェアをコメントアウトしていないelse
枝、else
枝が初期化ロジックのコア・ミドルウェア・コンポーネントです。最後の場所をするすべてのミドルウェアself._middleware_chain
本ミドルウェア処理チェーンここで私はそれを設計思考で理解したいためにかなりの時間を要しました。
次に展開else
コア部分に、ブロックを。他の内部以下のソースコードの一部を上場。
else:
# 这里是将handler赋初始值为self._get_response, 这个函数是用来匹配请求url与调用视图函数
# 并应用view, exception, template_response中间件.
handler = convert_exception_to_response(self._get_response)
# 接下来一段代码比较难理解, 但确是设计的精髓.
# 首先, 遍历我们配置的中间件列表, 只不过这里是逆序遍历, 至于为什么, 往下看就知道了
for middleware_path in reversed(settings.MIDDLEWARE):
# 这里是将我们配置的字符串形式的中间件类通过反射解析成类. 原理最后会简单分析
middleware = import_string(middleware_path)
try:
# 将中间件类实例化为一个对象, 这里把上一个handler当做参数
# 这也是能够将中间件通过一个初始化对象链式调用的精髓. 下面会有解释
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
# 实例化对象为None, 因为中间件还可以是函数形式
if mw_instance is None:
raise ImproperlyConfigured(
'Middleware factory %s returned None.' % middleware_path
)
# 将process_view方法添加到_view_middleware列表的开头
if hasattr(mw_instance, 'process_view'):
self._view_middleware.insert(0, mw_instance.process_view)
# 将process_template_response方法添加到_template_response_middleware列表的末尾
# 这里也能解释为什么处理模板以及下面的异常时逆序(按照注册顺序逆序)处理的
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变量
handler = convert_exception_to_response(mw_instance)
# 最后这个handler指向的是中间件列表的第一个实例对象
self._middleware_chain = handler
上記の分析の後、依然として困難、オブジェクトのインスタンス化ミドルウェアを見る必要の形式で定義されたアイデアを、理解するように定義された中間クラス以下のセクションを参照してくださいする必要があり、これを読んだ後、
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
各クラスは、ミドルウェアの2つの基本的な方法を持っているオブジェクトは、次GET_RESPONSE初期化されるとき、保存されます、最後のコールミドルウェアは、オブジェクトがGET_RESPONSEオブジェクトストアを呼び出して停止することはできませんインスタンス化し、これは、キーチェーンの呼び出しを達成することができるである。上記アイデアは数字が示して参照してください。
上記のコードでは、この時間を見に、第ハンドラ方法の出発点は、最内層をGET_RESPONSE、次いで最後の中間からリストをトラバース、パラメータとしてハンドラ(この場合に、GET_RESPONSE)、ミドルウェアはCommonMiddlewareオブジェクトを生成し、このハンドラは、新しいオブジェクトを指す場合、その後のサイクルでは、上記の動作、パッケージの1つの層の等価を繰り返します。
最後に、ハンドラは、ミドルウェアオブジェクトの最外層を指します。そして、に割り当てられたself._middleware_chain
変数。
我々が起動するとself._middleware_chain(request)
、このミドルウェア・トリガされたときにメソッドを__call__
アプローチ。ミドルウェアの最外層から今回の実装process_request
応答がない限りの方法を、それは常にミドルウェア変数トリガーの内層呼び出す__call__
まで、この方法を最も内側の層は、ビュー関連の機能の処理を開始。URLと一致した後、ビュー機能を呼び出す前に、すべてのprocess_view方法ミドルウェアを横断します。返された結果がNoneの場合は例外がトリガされた場合、呼び出しは、私たちのビュー機能を書くために、異常な資格のトリガーをprocess_template_response呼び出すしない方法は、同様にprocess_exceptionメソッドをトリガーする場合は、すべてにprocess_exception方法にプロセスを通過します。最後に、結果が戻って戻ります。そして、この時間は、最も内側からレイヤをレイヤに戻ります。このフック関数をトリガーするミドルウェアの順番を説明することができます。
ここでは、最も内側の一部の削除を処理ロジックを奪還
# django/core/handlers/base.py
def _get_response(self, request):
response = None
# 路由匹配
if hasattr(request, 'urlconf'):
urlconf = request.urlconf
set_urlconf(urlconf)
resolver = get_resolver(urlconf)
else:
resolver = get_resolver()
resolver_match = resolver.resolve(request.path_info)
# 这个callback就是我们的视图函数, 后两个是视图函数可能需要的参数
callback, callback_args, callback_kwargs = resolver_match
request.resolver_match = resolver_match
# 应用 view middleware 中间件
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs)
# 只要有response返回, 就立刻停止遍历
if response:
break
if response is None:
# 给视图函数包装一层
wrapped_callback = self.make_view_atomic(callback)
try:
# 这里是调用视图函数
response = wrapped_callback(request, *callback_args, **callback_kwargs)
except Exception as e:
# 有异常就进入exception view处理
response = self.process_exception_by_middleware(e, request)
# 这个不常用的process_template_response功能, 看源码可以清楚的知道为什么
# 返回的结果为啥需要有render方法了
elif hasattr(response, 'render') and callable(response.render):
for middleware_method in self._template_response_middleware:
response = middleware_method(request, response)
# ...
try:
response = response.render()
except Exception as e:
response = self.process_exception_by_middleware(e, request)
return response
概要
ソースコード解析の上の部分では、最終的にはミドルウェアが要求と応答を処理します。この順序に基づいている理由を理解することができます。Djangoはこのアイデアは、学習は非常に深い感情を終えた後、私は、再び接触していないで、唯一のため息ことができます他人へのプログラムの絶妙なデザインは、私も勉強したいと思います。