Flashkソース解読---要求から応答までの流れ
12708 ワード
flashkを学んで短い時間があって、ずっとソースコードを理解したくて、最近大神の1篇のブログの分析のとても透徹していることを見て、意外にも分かりました。
1.Flashkを持ち上げ、 話してください WSGI:
HTTPプロトコルとHTML文書を知ると、ウェブアプリケーションの本質が分かります。ブラウザでHTTP要求を送信する。 サーバが要求を受信し、HTML文書を作成する。 サーバは、HTML文書をHTTP応答のBodyとしてブラウザに送信する。 ブラウザはHTTP応答を受信し、HTTP BodyからHTML文書を取り出して表示する。 したがって、最も簡単なWebアプリケーションは、まずHTML用ファイルを保存し、既存のHTTPサーバソフトウェアを使って、ユーザーからの要求を受け、ファイルからHTMLを読み取り、戻ってきます。Apache、Nginx、Lighttpdなどの一般的な静的なサーバーはこのことをします。
HTMLを動的に生成するには、上記の手順を自分で行う必要があります。しかし、HTTPの要求を受け入れて、HTTPの要求を解析して、HTTPの応答を発送するのはすべて努力して生きるので、もし私達は自分でこれらの底のコードを書きにくるならば、まだ動的なHTMLを書くことを始めていないで、1ヶ月を使ってHTTP規範を読みに行きます。
正確なやり方は、下のコードは専門的なサーバーソフトウェアによって実現されます。Pythonを使ってHTML文書の作成に専念します。TCP接続、HTTPの元の要求と応答フォーマットに接触したくないので、統一したインターフェースが必要です。Pythonを使ってWebサービスを作成します。
このインターフェースはWSGI:Web Server Gateway Interfaceです。
2.WSGIの具体的な機能:
wsgiはインターフェースの役割を果たすことができます。前のドッキングサーバー、後のドッキングアプリの具体的な機能です。
WSGIインターフェースの定義は非常に簡単で、Web開発者に一つの関数を実現するだけでHTTP要求に応答できる。簡単なWebバージョンの「ハロー、web!」を見てみましょう。 environ:すべてのHTTP要求情報を含む start_レスポンス:HTTP応答を送信する関数 3.FlashkとWSGI
しかし、アプリを呼び出すと、実際にFlashkの__uを呼び出します。コールバック方法は、これがアプリの仕事の始まりです。
Flaaskの__u uコールバックソースは以下の通りです
wsgiに来てくださいアプリはどのように定義されていますか
ctx=self.request_が見られます。context(environ)は、要求コンテキストとアプリケーションコンテキストの概念を設計し、構造はスタック構造であり、スタックの特徴を持つ。
request要求オブジェクトの生成及び要求情報を含むrequest_context
第二のステップは、前処理、エラー処理、および応答を要求するプロセスである。
ステップ3 ディスプレーをお願いします。request:
続いてfull_dispatch_request()はmakeを通過するレスポンスはrvをレスポンスとして発生し、レスポンスはレスポンスとして与えられます。
そのメークレスリングはどうやってできますか?ソースを見てください。
HTTP requestからレスポンスまでの流れは終わりました。
流れを整理する:
クライアント-->wsgi server-->を通じてコールバックwsgiを呼び出しますアプリ、 requestsオブジェクトとコンテキスト環境を生成する-->full_dispatch_request機能-->dispatchを通じてrequestsはurlからview functionへの論理転送を行い、リターン値を取得する-->make_レスポンス関数は、viewを使います。Functionの戻り値は、レスポンス_に変換されます。classの対象--->レスポンスの対象にはenvironとstart_が入ってきます。レスポンスパラメータは、最終応答をサーバに返します。
一人でソースコードを読み终わるのは本当に容易ではありません。頑張ってください。ここを見たプログラムをみんなに送ってください。
1.Flashkを持ち上げ、 話してください WSGI:
HTTPプロトコルとHTML文書を知ると、ウェブアプリケーションの本質が分かります。
HTMLを動的に生成するには、上記の手順を自分で行う必要があります。しかし、HTTPの要求を受け入れて、HTTPの要求を解析して、HTTPの応答を発送するのはすべて努力して生きるので、もし私達は自分でこれらの底のコードを書きにくるならば、まだ動的なHTMLを書くことを始めていないで、1ヶ月を使ってHTTP規範を読みに行きます。
正確なやり方は、下のコードは専門的なサーバーソフトウェアによって実現されます。Pythonを使ってHTML文書の作成に専念します。TCP接続、HTTPの元の要求と応答フォーマットに接触したくないので、統一したインターフェースが必要です。Pythonを使ってWebサービスを作成します。
このインターフェースはWSGI:Web Server Gateway Interfaceです。
2.WSGIの具体的な機能:
wsgiはインターフェースの役割を果たすことができます。前のドッキングサーバー、後のドッキングアプリの具体的な機能です。
WSGIインターフェースの定義は非常に簡単で、Web開発者に一つの関数を実現するだけでHTTP要求に応答できる。簡単なWebバージョンの「ハロー、web!」を見てみましょう。
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return 'Hello, web!'
上記のアプリアプリ()関数はWSGI規格に適合するHTTP処理関数で、二つのパラメータを受信します。dict
オブジェクト。from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World!'
このようにflashkのインスタンスが生成されます。しかし、アプリを呼び出すと、実際にFlashkの__uを呼び出します。コールバック方法は、これがアプリの仕事の始まりです。
Flaaskの__u uコールバックソースは以下の通りです
class Flask(_PackageBoundObject):
#
def __call__(self, environ, start_response): # Flask __call__
"""Shortcut for :attr:`wsgi_app`."""
return self.wsgi_app(environ, start_response)
ですから、要請が来たら、_u_u uを呼び出しました。コールバック方法はありますが、実際に呼び出しが見られます。appメソッドは、パラメータenvironとsart_に同時に伝わります。レスポンスwsgiに来てくださいアプリはどのように定義されていますか
def wsgi_app(self, environ, start_response):
"""The actual WSGI application. This is not implemented in
`__call__` so that middlewares can be applied without losing a
reference to the class. So instead of doing this::
app = MyMiddleware(app)
It's a better idea to do this instead::
app.wsgi_app = MyMiddleware(app.wsgi_app)
Then you still have the original application object around and
can continue to call methods on it.
.. versionchanged:: 0.7
The behavior of the before and after request callbacks was changed
under error conditions and a new callback was added that will
always execute at the end of the request, independent on if an
error occurred or not. See :ref:`callbacks-and-errors`.
:param environ: a WSGI environment
:param start_response: a callable accepting a status code,
a list of headers and an optional
exception context to start the response
"""
ctx = self.request_context(environ)
ctx.push()
error = None
try:
try:
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
第1のステップは、request要求オブジェクトと要求コンテキスト環境を生成する。ctx=self.request_が見られます。context(environ)は、要求コンテキストとアプリケーションコンテキストの概念を設計し、構造はスタック構造であり、スタックの特徴を持つ。
request要求オブジェクトの生成及び要求情報を含むrequest_context
第二のステップは、前処理、エラー処理、および応答を要求するプロセスである。
response = self.full_dispatch_request()
応答が与えられた値に応じてフルフルになりました。dispatch_request()ですので、フルートを見てください。dispatch_request()方法 def full_dispatch_request(self):
"""Dispatches the request and on top of that performs request
pre and postprocessing as well as HTTP exception catching and
error handling.
.. versionadded:: 0.7
"""
self.try_trigger_before_first_request_functions() # ,
try:
request_started.send(self) # socket
rv = self.preprocess_request() #
if rv is None:
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
return self.finalize_request(rv)
とりあえずtryを見てくださいトリガー_before_first_request_functions()は、最終的には_をgotfirst_requestはTrueに設定されています。Trueであれば、リクエストの処理を開始します。 def try_trigger_before_first_request_functions(self):
"""Called before each request and will ensure that it triggers
the :attr:`before_first_request_funcs` and only exactly once per
application instance (which means process usually).
:internal:
"""
if self._got_first_request:
return
with self._before_request_lock:
if self._got_first_request:
return
for func in self.before_first_request_funcs:
func()
self._got_first_request = True
gotfirst_request()は静的方法と定義されており、定義にはifが見られます。 the appication started、this atribute is set to True.class Flask(_PackageBoundObject):
# ...
@property
def got_first_request(self):
"""This attribute is set to ``True`` if the application started
handling the first request.
.. versionadded:: 0.8
"""
return self._got_first_request
フルに戻るdispatch_request()、preprocessを見てください。request()方法、つまりflashkのフックは、中間キーに相当しています。before gauを実現できます。request機能. try:
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
dispatchに対してrequest()方法は、配布要求の役割を果たしています。一つの要求はurlを通じて送られてきました。この方法を通してステップ3 ディスプレーをお願いします。request:
def dispatch_request(self):
"""Does the request dispatching. Matches the URL and returns the
return value of the view or error handler. This does not have to
be a response object. In order to convert the return value to a
proper response object, call :func:`make_response`.
.. versionchanged:: 0.7
This no longer does the exception handling, this code was
moved to the new :meth:`full_dispatch_request`.
"""
req = _request_ctx_stack.top.request # req
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule
# if we provide automatic options for this URL and the
# request came with the OPTIONS method, reply automatically
if getattr(rule, 'provide_automatic_options', False) \
and req.method == 'OPTIONS':
return self.make_default_options_response()
# otherwise dispatch to the handler for that endpoint
return self.view_functions[rule.endpoint](**req.view_args)
このステップの主な役割は@app.route('/')の'/'とindex関数を対応させることです。続いてfull_dispatch_request()はmakeを通過するレスポンスはrvをレスポンスとして発生し、レスポンスはレスポンスとして与えられます。
そのメークレスリングはどうやってできますか?ソースを見てください。
def make_response(self, rv):
"""Converts the return value from a view function to a real
response object that is an instance of :attr:`response_class`.
The following types are allowed for `rv`:
.. tabularcolumns:: |p{3.5cm}|p{9.5cm}|
======================= ===========================================
:attr:`response_class` the object is returned unchanged
:class:`str` a response object is created with the
string as body
:class:`unicode` a response object is created with the
string encoded to utf-8 as body
a WSGI function the function is called as WSGI application
and buffered as response object
:class:`tuple` A tuple in the form ``(response, status,
headers)`` or ``(response, headers)``
where `response` is any of the
types defined here, `status` is a string
or an integer and `headers` is a list or
a dictionary with header values.
======================= ===========================================
:param rv: the return value from the view function
.. versionchanged:: 0.9
Previously a tuple was interpreted as the arguments for the
response object.
"""
status_or_headers = headers = None
if isinstance(rv, tuple):
rv, status_or_headers, headers = rv + (None,) * (3 - len(rv))
if rv is None:
raise ValueError('View function did not return a response')
if isinstance(status_or_headers, (dict, list)):
headers, status_or_headers = status_or_headers, None
if not isinstance(rv, self.response_class):
# When we create a response object directly, we let the constructor
# set the headers and status. We do this because there can be
# some extra logic involved when creating these objects with
# specific values (like default content type selection).
if isinstance(rv, (text_type, bytes, bytearray)):
rv = self.response_class(rv, headers=headers,
status=status_or_headers)
headers = status_or_headers = None
else:
rv = self.response_class.force_type(rv, request.environ)
if status_or_headers is not None:
if isinstance(status_or_headers, string_types):
rv.status = status_or_headers
else:
rv.status_code = status_or_headers
if headers:
rv.headers.extend(headers)
return rv
第四歩は、wsgi_に戻る。アプリの内部: def wsgi_app(self, environ, start_response):
"""The actual WSGI application. This is not implemented in
`__call__` so that middlewares can be applied without losing a
reference to the class. So instead of doing this::
app = MyMiddleware(app)
It's a better idea to do this instead::
app.wsgi_app = MyMiddleware(app.wsgi_app)
Then you still have the original application object around and
can continue to call methods on it.
.. versionchanged:: 0.7
The behavior of the before and after request callbacks was changed
under error conditions and a new callback was added that will
always execute at the end of the request, independent on if an
error occurred or not. See :ref:`callbacks-and-errors`.
:param environ: a WSGI environment
:param start_response: a callable accepting a status code,
a list of headers and an optional
exception context to start the response
"""
ctx = self.request_context(environ)
ctx.push()
error = None
try:
try:
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
このままレスポンスがフルからdispatch_request()で入手した後、パラメータenvironとstart_に入る。レスポンス、Gunnicornに戻りました。HTTP requestからレスポンスまでの流れは終わりました。
流れを整理する:
クライアント-->wsgi server-->を通じてコールバックwsgiを呼び出しますアプリ、 requestsオブジェクトとコンテキスト環境を生成する-->full_dispatch_request機能-->dispatchを通じてrequestsはurlからview functionへの論理転送を行い、リターン値を取得する-->make_レスポンス関数は、viewを使います。Functionの戻り値は、レスポンス_に変換されます。classの対象--->レスポンスの対象にはenvironとstart_が入ってきます。レスポンスパラメータは、最終応答をサーバに返します。
一人でソースコードを読み终わるのは本当に容易ではありません。頑張ってください。ここを見たプログラムをみんなに送ってください。