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!」を見てみましょう。
    def application(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return '

    Hello, web!

    '
    上記のアプリアプリ()関数はWSGI規格に適合するHTTP処理関数で、二つのパラメータを受信します。
  • environ:すべてのHTTP要求情報を含むdictオブジェクト。
  • start_レスポンス:HTTP応答を送信する関数
  • 3.FlashkとWSGI
    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_が入ってきます。レスポンスパラメータは、最終応答をサーバに返します。
    一人でソースコードを読み终わるのは本当に容易ではありません。頑張ってください。ここを見たプログラムをみんなに送ってください。