apeescape2.com
  • メイン
  • その他
  • モバイル
  • ツールとチュートリアル
  • ライフスタイル
バックエンド

WSGI:Python用のサーバー-アプリケーションインターフェイス

1993年、ウェブはまだ揺籃期にあり、 1,400万人のユーザーと100のウェブサイト 。ページは静的でしたが、最新のニュースやデータなどの動的なコンテンツを作成する必要がすでにありました。これに応えて、Rob McCoolと他の貢献者は、National Center for Supercomputing Applications(NCSA)にCommon Gateway Interface(CGI)を実装しました。 HTTPdWebサーバー (Apacheの前身)。これは、別のアプリケーションによって生成されたコンテンツを提供できる最初のWebサーバーでした。

それ以来、インターネット上のユーザー数は爆発的に増加し、動的なWebサイトは至る所に存在するようになりました。開発者は、新しい言語を最初に学習するとき、またはコードを最初に学習するときでさえ、すぐにコードをWebにフックする方法について知りたいと思っています。

Python on theWebとWSGIの台頭

CGIの作成以来、多くの変化がありました。 CGIアプローチは、要求ごとに新しいプロセスを作成する必要があり、メモリとCPUを浪費するため、実用的ではなくなりました。 FastCGI](http://www.fastcgi.com/)(1996)やなど、他のいくつかの低レベルのアプローチが登場しました。 mod_python (2000)、PythonWebフレームワークとWebサーバーの間に異なるインターフェースを提供します。さまざまなアプローチが急増するにつれて、開発者によるフレームワークの選択がWebサーバーの選択を制限することになり、その逆も同様でした。



この問題に対処するために、2003年にPhillip J.Ebyは提案しました PEP-0333 、Python Web Server Gateway Interface(WSGI)。アイデアは、PythonアプリケーションとWebサーバーの間に高レベルのユニバーサルインターフェイスを提供することでした。

2003年、 PEP-3333 WSGIインターフェイスを更新して、Python3のサポートを追加しました。現在、ほとんどすべてのPythonフレームワークは、Webサーバーと通信するための手段としてWSGIを使用しています。こうやって Django 、 フラスコ そして他の多くの人気のあるフレームワークがそれを行います。

この記事は、WSGIがどのように機能するかを読者に垣間見せ、読者が単純なWSGIアプリケーションまたはサーバーを構築できるようにすることを目的としています。ただし、これは網羅的なものではありません。本番環境に対応したサーバーまたはアプリケーションを実装する予定の開発者は、 WSGI仕様 。

PythonWSGIインターフェース

WSGIは、サーバーとアプリケーションが準拠する必要のある単純なルールを指定します。この全体的なパターンを確認することから始めましょう。

PythonWSGIサーバー-アプリケーションインターフェイス。

アプリケーションインターフェイス

Python 3.5では、アプリケーションインターフェイスは次のようになります。

def application(environ, start_response): body = b'Hello world! ' status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) return [body]

Python 2.7では、このインターフェースはそれほど変わりません。唯一の変更点は、本体がstrで表されることです。 bytesの代わりにオブジェクト1。

この場合は関数を使用しましたが、 呼び出し可能 しましょう。ここでのアプリケーションオブジェクトのルールは次のとおりです。

  • environで呼び出し可能である必要がありますおよびstart_responseパラメーター。
  • start_responseを呼び出す必要があります本文を送信する前にコールバックします。
  • ドキュメント本文の一部で反復可能を返す必要があります。

これらのルールを満たし、同じ効果を生み出すオブジェクトの別の例は次のとおりです。

class Application: def __init__(self, environ, start_response): self.environ = environ self.start_response = start_response def __iter__(self): body = b'Hello world! ' status = '200 OK' headers = [('Content-type', 'text/plain')] self.start_response(status, headers) yield body

サーバーインターフェース

WSGIサーバーは、次のようにこのアプリケーションとインターフェイスする場合があります。

def write(chunk): '''Write data back to client''' ... def send_status(status): '''Send HTTP status code''' ... def send_headers(headers): '''Send HTTP headers''' ... def start_response(status, headers): '''WSGI start_response callable''' send_status(status) send_headers(headers) return write # Make request to application response = application(environ, start_response) try: for chunk in response: write(chunk) finally: if hasattr(response, 'close'): response.close()

お気づきかもしれませんが、start_response callableはwriteを返しましたアプリケーションがクライアントにデータを送り返すために使用する可能性がある呼び出し可能ですが、アプリケーションのコード例では使用されていません。これwriteインターフェイスは非推奨であり、今のところ無視できます。これについては、この記事の後半で簡単に説明します。

サーバーの責任のもう1つの特徴は、オプションのcloseを呼び出すことです。応答イテレータのメソッド(存在する場合)。グラハム・ダンプルトンの記事で指摘されているように ここに 、これはWSGIの見過ごされがちな機能です。このメソッドを呼び出すと、 存在する場合 、アプリケーションがまだ保持している可能性のあるリソースを解放できるようにします。

ApplicationCallableのenviron引数

environパラメータは辞書オブジェクトである必要があります。これは、CGIとほぼ同じ方法で、要求およびサーバー情報をアプリケーションに渡すために使用されます。実際、すべてのCGI環境変数はWSGIで有効であり、サーバーはアプリケーションに適用されるすべてのものを渡す必要があります。

渡すことができるオプションのキーはたくさんありますが、いくつかは必須です。例として、次のGETリクエスト:

$ curl 'http://localhost:8000/auth?user=obiwan&token=123'

これらはサーバーが使用するキーです しなければならない 提供し、それらが取る値:

キー 値 コメント
REQUEST_METHOD 'GET'
SCRIPT_NAME '' サーバーのセットアップに依存
PATH_INFO '/auth'
QUERY_STRING 'token=123'
CONTENT_TYPE ''
CONTENT_LENGTH ''
SERVER_NAME '127.0.0.1' サーバーのセットアップに依存
SERVER_PORT '8000'
SERVER_PROTOCOL 'HTTP/1.1'
HTTP_(...) クライアント提供のHTTPヘッダー
wsgi.version (1, 0) WSGIバージョンのタプル
wsgi.url_scheme 'http'
wsgi.input ファイルのようなオブジェクト
wsgi.errors ファイルのようなオブジェクト
wsgi.multithread False Trueサーバーがマルチスレッドの場合
wsgi.multiprocess False Trueサーバーが複数のプロセスを実行する場合
wsgi.run_once False Trueサーバーがこのスクリプトが1回だけ実行されることを期待している場合(例:CGI環境で)

この規則の例外は、これらのキーの1つが空の場合(上記の表のCONTENT_TYPEのように)、辞書から省略でき、空の文字列に対応していると見なされることです。

wsgi.inputおよびwsgi.errors

ほとんどenvironキーは単純ですが、そのうちの2つはもう少し明確にする必要があります。wsgi.inputはクライアントからのリクエスト本文を含むストリームを含む必要があり、wsgi.errorsはアプリケーションが発生したエラーを報告します。アプリケーションからwsgi.errorsに送信されたエラー通常、サーバーのエラーログに送信されます。

これらの2つのキーには、ファイルのようなオブジェクトが含まれている必要があります。つまり、Pythonでファイルまたはソケットを開いたときに取得するオブジェクトと同じように、ストリームとして読み取りまたは書き込みを行うインターフェイスを提供するオブジェクトです。これは最初は難しいように思えるかもしれませんが、幸いなことに、Pythonはこれを処理するための優れたツールを提供してくれます。

まず、どのようなストリームについて話しているのですか? WSGIの定義によると、wsgi.inputおよびwsgi.errors bytesを処理する必要がありますPython3およびstrのオブジェクトPython 2のオブジェクト。いずれの場合も、メモリ内バッファを使用してWSGIインターフェイスを介してデータを渡したり取得したりする場合は、クラスio.BytesIOを使用できます。

例として、WSGIサーバーを作成している場合、次のようにアプリケーションにリクエスト本文を提供できます。

  • Python2.7の場合
import io ... request_data = 'some request body' environ['wsgi.input'] = io.BytesIO(request_data)
  • Python3.5の場合
import io ... request_data = 'some request body'.encode('utf-8') # bytes object environ['wsgi.input'] = io.BytesIO(request_data)

アプリケーション側では、受け取ったストリーム入力を文字列に変換する場合は、次のように記述します。

  • Python2.7の場合
readstr = environ['wsgi.input'].read() # returns str object
  • Python3.5の場合
readbytes = environ['wsgi.input'].read() # returns bytes object readstr = readbytes.decode('utf-8') # returns str object

wsgi.errorsストリームはアプリケーションエラーをサーバーに報告するために使用する必要があり、行は で終了する必要があります。 Webサーバーは、システムに応じて終了する別の行への変換を処理する必要があります。

ApplicationCallableのstart_response引数

start_response引数は、2つの必須引数、つまりstatusを持つ呼び出し可能である必要があります。およびheaders、および1つのオプションの引数exc_info。本体の一部がWebサーバーに返送される前に、アプリケーションによって呼び出される必要があります。

この記事の冒頭にある最初のアプリケーション例では、応答の本文をリストとして返したため、リストがいつ繰り返されるかを制御することはできません。このため、start_responseに電話する必要がありましたリストを返す前に。

2つ目では、start_responseと呼びました応答本体の最初の(この場合は唯一の)部分を生成する直前。どちらの方法もWSGI仕様内で有効です。

Webサーバー側から、start_responseの呼び出し実際にヘッダーをクライアントに送信するべきではありませんが、クライアントに送り返すために応答本文に空でないバイト文字列が少なくとも1つあるまでヘッダーを遅らせます。このアーキテクチャにより、アプリケーションの実行の最後の可能な瞬間まで、エラーを正しく報告できます。

status start_responseの引数

status start_responseに渡される引数コールバックは、HTTPステータスコードと説明で構成され、単一のスペースで区切られた文字列である必要があります。有効な例は、'200 OK'または'404 Not Found'です。

headers start_responseの引数

headers start_responseに渡される引数コールバックはPythonでなければなりませんlist tuple sの、各タプルは(header_name, header_value)として構成されます。各ヘッダーの名前と値は両方とも文字列である必要があります(Pythonのバージョンに関係なく)。これは、WSGI仕様で実際に要求されているため、タイプが重要となるまれな例です。

これは、headerの有効な例です。引数は次のようになります。

response_body = json.dumps(data).encode('utf-8') headers = [('Content-Type', 'application/json'), ('Content-Length', str(len(response_body))]

HTTPヘッダーでは大文字と小文字が区別されません。また、WSGI準拠のWebサーバーを作成している場合は、これらのヘッダーを確認するときに注意する必要があります。また、アプリケーションによって提供されるヘッダーのリストは網羅的ではありません。応答をクライアントに送り返す前に、必要なすべてのHTTPヘッダーが存在することを確認し、アプリケーションによって提供されていないヘッダーを入力するのはサーバーの責任です。

exc_info start_responseの引数

start_responseコールバックは、エラー処理に使用される3番目の引数exc_infoをサポートする必要があります。この引数の正しい使用法と実装は、本番Webサーバーとアプリケーションにとって最も重要ですが、この記事の範囲外です。

詳細については、WSGI仕様で入手できます。 ここに 。

start_response戻り値– write折り返し電話

下位互換性のために、WSGIを実装するWebサーバーはwriteを返す必要があります。呼び出し可能。このコールバックにより、アプリケーションは、イテレータを介してサーバーにデータを渡すのではなく、本文の応答データをクライアントに直接書き戻すことができます。

その存在にもかかわらず、これは非推奨のインターフェースであり、新しいアプリケーションはそれを使用しないようにする必要があります。

llc c vs llc s

レスポンスボディの生成

WSGIを実装するアプリケーションは、反復可能なオブジェクトを返すことによって応答本文を生成する必要があります。ほとんどのアプリケーションでは、応答本体はそれほど大きくなく、サーバーのメモリに簡単に収まります。その場合、それを送信する最も効率的な方法は、1つの要素を反復可能にして一度に送信することです。全身をメモリにロードすることが不可能な特殊なケースでは、アプリケーションはこの反復可能なインターフェイスを介して部分的にそれを返す場合があります。

ここでは、Python2とPython3のWSGIの違いはわずかです。Python3では、応答の本文はbytesで表されます。オブジェクト; Python 2では、これの正しいタイプはstrです。

UTF-8文字列をbytesに変換するまたはstr簡単な作業です:

  • Python 3.5:
body = 'unicode stuff'.encode('utf-8')
  • Python 2.7:
body = u'unicode stuff'.encode('utf-8')

Python 2のUnicodeとバイト文字列の処理について詳しく知りたい場合は、次のチュートリアルをご覧ください。 Youtube 。

WSGIを実装するWebサーバーもwriteをサポートする必要があります上記のように、下位互換性のためのコールバック。

Webサーバーなしでアプリケーションをテストする

このシンプルなインターフェイスを理解すれば、実際にサーバーを起動しなくても、アプリケーションをテストするためのスクリプトを簡単に作成できます。

この小さなスクリプトを例にとってみましょう。

from io import BytesIO def get(app, path = '/', query = ''): response_status = [] response_headers = [] def start_response(status, headers): status = status.split(' ', 1) response_status.append((int(status[0]), status[1])) response_headers.append(dict(headers)) environ = { 'HTTP_ACCEPT': '*/*', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_USER_AGENT': 'TestAgent/1.0', 'PATH_INFO': path, 'QUERY_STRING': query, 'REQUEST_METHOD': 'GET', 'SERVER_NAME': '127.0.0.1', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'TestServer/1.0', 'wsgi.errors': BytesIO(b''), 'wsgi.input': BytesIO(b''), 'wsgi.multiprocess': False, 'wsgi.multithread': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0), } response_body = app(environ, start_response) merged_body = ''.join((x.decode('utf-8') for x in response_body)) if hasattr(response_body, 'close'): response_body.close() return {'status': response_status[0], 'headers': response_headers[0], 'body': merged_body}

このようにして、たとえば、いくつかのテストデータとモックモジュールをアプリに初期化し、GETを作成することができます。それに応じて応答するかどうかをテストするために呼び出します。これは実際のウェブサーバーではないことがわかりますが、アプリケーションにstart_responseを提供することで、同等の方法でアプリとやり取りします。コールバックと環境変数を含む辞書。リクエストの最後に、レスポンスボディのイテレータを使用して、すべてのコンテンツを含む文字列を返します。同様のメソッド(または一般的なメソッド)は、さまざまなタイプのHTTP要求に対して作成できます。

要約

WSGIは、ほとんどすべてのPythonWebフレームワークの重要な部分です。

この記事では、WSGIがファイルのアップロードを処理する方法については触れていません。これは、紹介記事には適さない、より「高度な」機能と見なされる可能性があるためです。それについてもっと知りたい場合は、 ファイル処理に言及しているPEP-3333セクション 。

この記事が、PythonがWebサーバーとどのように通信するかをよりよく理解するのに役立ち、開発者がこのインターフェイスを面白くて創造的な方法で使用できるようになることを願っています。

謝辞

編集者に感謝します ニック・マクリー この記事を手伝ってくれて。彼の仕事のおかげで、元のテキストははるかに明確になり、いくつかのエラーは修正されませんでした。

SVGアニメーションのハウツーガイド

Webフロントエンド

SVGアニメーションのハウツーガイド
非同期JavaScript:コールバック地獄から非同期と待機まで

非同期JavaScript:コールバック地獄から非同期と待機まで

バックエンド

人気の投稿
.NETCore-ワイルドでオープンソース化。マイクロソフト、どうしてそんなに時間がかかったの?
.NETCore-ワイルドでオープンソース化。マイクロソフト、どうしてそんなに時間がかかったの?
パーム油への投資家向けガイド
パーム油への投資家向けガイド
B2B UX –一般的な障害と達成可能なソリューション
B2B UX –一般的な障害と達成可能なソリューション
フレーマーチュートリアル:プロトタイプを改善するための7つの簡単なマイクロインタラクション
フレーマーチュートリアル:プロトタイプを改善するための7つの簡単なマイクロインタラクション
フリーランスのファイナンスコンサルタントが大企業をどのように打ち負かしているか
フリーランスのファイナンスコンサルタントが大企業をどのように打ち負かしているか
 
成功する市場開拓戦略を作成する方法
成功する市場開拓戦略を作成する方法
ブロックチェーンID管理:データセキュリティ革命の火付け役
ブロックチェーンID管理:データセキュリティ革命の火付け役
より軽く、より速く-Svelteフレームワークのガイド
より軽く、より速く-Svelteフレームワークのガイド
UXポートフォリオのヒントとベストプラクティス
UXポートフォリオのヒントとベストプラクティス
フリーランサーの個人情報の盗難:それは私に起こりました—これがあなたが知っておくべきことです
フリーランサーの個人情報の盗難:それは私に起こりました—これがあなたが知っておくべきことです
人気の投稿
  • どのタイプのLLCが私ですか
  • ノードjsフルスタックフレームワーク
  • 2017年に販売されたドローンの数
  • システムからユーザーファイルを取得して、別のコンピューターに移行できるようにするプログラムはどれですか。
  • オブジェクトの属性の例は次のとおりです。
カテゴリー
ヒントとツール データサイエンスとデータベース Uxデザイン 計画と予測 ツールとチュートリアル 財務プロセス トレンド 投資家と資金調達 Webフロントエンド 分散チーム

© 2021 | 全著作権所有

apeescape2.com