この記事は MaNong.com の Xiao Hao によって翻訳されたものです。転載については記事の最後にある転載要件をお読みください。有料投稿プランへの参加を歓迎します。
Django、Flask、Bottle、およびその他すべての Python Web フレームワークの基礎となっているのは、Web サーバー ゲートウェイ インターフェイス (略して WSGI) です。 Python にとっての WSGI は、Java にとってのサーブレットに相当します。これは、さまざまな Web サーバーとアプリケーション フレームワークが共通の API に基づいて対話できるようにする Web サーバーの共通仕様です。ただし、ほとんどの場合、Python バージョンの実装は非常に簡単です。
WSGI は PEP 3333 プロトコルで定義されています。この記事を読んだ後にさらに詳しく知りたい場合は、まずはじめに読むことをお勧めします。
この記事では、アプリケーション開発者の観点から WSGI の手順を紹介し、(待ちきれない場合に) WSGI を介して直接アプリケーションを開発する方法を示します。
これが最も基本的な Python Web アプリケーションです:
def app(environ, start_fn): start_fn('200 OK', [('Content-Type', 'text/plain')]) return ["Hello World!\n"]
以上です!ファイル全体。まず、app.py という名前を付けて、WSGI コンパイル可能なサーバー上で実行すると、200 応答ステータス コードを含む Hello World が返されます。これを行うには、gunicorn を使用し、pip 経由で gunicorn app:app をインストールして実行します (pip install gunicorn)。このコマンドは、アプリケーション モジュールのアプリケーション変数から WSGI 呼び出し可能ファイルを取得するように gunicorn に指示します。
今とても興奮していました。たった 3 行のコードでアプリケーションを実行できますか?これはある意味でのログ記録に違いありません (mod_php が機能しているため、PHP は除きます)。きっと今からもっと詳しく知りたいと思うでしょう。
それでは、WSGI アプリケーションの最も重要な部分は何でしょうか?
WSGI アプリケーションは、関数、クラス、または __call__ メソッドを持つクラス インスタンスのような Python 呼び出し可能なアプリケーションです
呼び出し可能なアプリケーションは 2 つのパラメーターを受け入れる必要があります: environ、必要なデータを含む Python 辞書、start_fn、それ自体は呼び出し可能です。
アプリケーションは、ステータス コード (文字列)、および 2 つのタプルのヘッダーで表されるリストの 2 つのパラメーターを使用して start_fn を呼び出すことができなければなりません。
アプリケーションは、戻り本体 (ストリーミング部分) にバイトを含む便利な反復可能なオブジェクト (たとえば、「Hello, World!」文字列のみを含むリスト) を返します。 (appがクラスの場合、__iter__メソッドで実行できます)
たとえば、次の2つの例は最初の例と同等です:
class app(object): def __init__(self, environ, start_fn): self.environ = environ self.start_fn = start_fn def __iter__(self): self.start_fn('200 OK', [('Content-Type', 'text/plain')]) yield "Hello World!\n"
class Application(object): def __call__(self, environ, start_fn): start_fn('200 OK', [('Content-Type', 'text/plain')]) yield "Hello World!\n" app = Application()
これらの使用方法を考え始めているかもしれません。それが何をするかですが、最も関連性があるのはミドルウェアの作成です。
ミドルウェアは、WSGI アプリケーションの機能を拡張する便利な方法です。呼び出し可能なオブジェクトを提供するだけでよいため、それを他の関数でラップできます。
たとえば、environの内容を検出したいとします。次のようなミドルウェアを簡単に作成できます:
import pprint def handler(environ, start_fn): start_fn('200 OK', [('Content-Type', 'text/plain')]) return ["Hello World!\n"] def log_environ(handler): def _inner(environ, start_fn): pprint.pprint(environ) return handler(environ, start_fn) return _inner app = log_environ(handler)
ここで、log_environは、元のコールバックを遅延させる前にenvironパラメータを装飾する関数を返す関数です。
この方法でミドルウェアを作成する利点は、ミドルウェアとプロセッサーがお互いを認識したり気にしたりする必要がないことです。たとえば、Flask アプリケーションは WSGI アプリケーションであるため、log_environ を Flask アプリケーションに簡単にバインドできます。
その他の便利なミドルウェア設計:
import pprint def handle_error(handler): def _inner(environ, start_fn): try: return handler(environ, start_fn) except Exception as e: print e # Log error start_fn('500 Server Error', [('Content-Type', 'text/plain')]) return ['500 Server Error'] return _inner def wrap_query_params(handler): def _inner(environ, start_fn): qs = environ.get('QUERY_STRING') environ['QUERY_PARAMS'] = urlparse.parse_qs(qs) return handler(environ, start_fn) return _inner
ファイルに大きなピラミッドベースを持たせたくない場合は、reduceを使用して複数のミドルウェアに一度に適用できます。
# Applied from bottom to top on the way in, then top to bottom on the way out MIDDLEWARES = [wrap_query_params, log_environ, handle_error] app = reduce(lambda h, m: m(h), MIDDLEWARES, handler)
start_fn パラメーターの利点を利用して、応答本文を装飾するミドルウェアを作成することもできます。以下は、コンテンツタイプヘッダーが text/plain で、出力結果を反転するミドルウェアです。
def reverser(handler): # A reverse function rev = lambda it: it[::-1] def _inner(environ, start_fn): do_reverse = [] # Must be a reference type such as a list # Override start_fn to check the content type and set a flag def start_reverser(status, headers): for name, value in headers: if (name.lower() == 'content-type' and value.lower() == 'text/plain'): do_reverse.append(True) break # Remember to call `start_fn` start_fn(status, headers) response = handler(environ, start_reverser) try: if do_reverse: return list(rev(map(rev, response))) return response finally: if hasattr(response, 'close'): response.close() return _inner
start_fn とレスポンスボディが分離されているため少し混乱していますが、それでも完全に機能します。
また、WSGI 仕様に厳密に従うためには、応答本文の close メソッドを確認し、存在する場合はそれを呼び出す必要があることにも注意してください。 WSGI アプリケーションが、ハンドラーを呼び出す反復可能オブジェクトの代わりに write 関数を返す可能性があります。ミドルウェアで古いアプリケーションをサポートしたい場合は、これに対処する必要がある場合があります。
ネイティブ WSGI を少しいじり始めると、Python に多数の Web フレームワークがある理由がわかり始めます。 WSGI を使用すると、何かを一から構築することが非常に簡単になります。たとえば、次のルーティング問題を検討しているとします。
routes = { '/': home_handler, '/about': about_handler, } class Application(object): def __init__(self, routes): self.routes = routes def not_found(self, environ, start_fn): start_fn('404 Not Found', [('Content-Type', 'text/plain')]) return ['404 Not Found'] def __call__(self, environ, start_fn): handler = self.routes.get(environ.get('PATH_INFO')) or self.not_found return handler(environ, start_fn)
次のリソース コレクションの柔軟性が気に入っている場合は、WSGI を直接使用してホイールを構築するのが非常に便利です。
テンプレート ライブラリ: 好きなテンプレート (Jinja2、Pystashe など) を放り込み、プロセッサからレンダリングされたテンプレートを返します。
Routes や Werkzeug のルーティングなど、ルーティングに役立つライブラリを使用します。実際、WSGI を簡単に使用したい場合は、Werkzeug を見てください。
Flask または同様のデータベース移行ライブラリを使用します。
もちろん、非専門的なアプリケーションの場合は、このような特殊な例も合理的に解決できるように、フレームワークを使用することもできます。
WSGI アプリケーションを提供する方法はたくさんあります。かなり良い選択である Gunicorn についてはすでに説明しました。 uWSGI も良い選択肢です。ただし、これらの静的なものを提供する前に、必ず nginx などをセットアップしてください。開始ノードは固定されている必要があります。
以上がPython Web アプリケーション: WSGI の基本の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。