リクエストの取得 (WSGI) | Python-izm

リクエストの取得 (WSGI)

PythonにおけるWSGIに対応したリクエスト処理となります。Python 3系におけるWSGIアプリケーションでは、returnで結果を返す際にencodeでbytesへ変換する必要があります。
※CGIでのリクエストの取得方法は「リクエストの取得 (CGI)」をご覧ください。

GET

GETリクエストの処理方法は下記の通りとなります。

import cgi
from wsgiref.simple_server import make_server


# HTML文字列
html = '''
<!DOCTYPE html>
<html>
  <head>
    <title>WSGI</title>
    <meta charset="UTF-8">
  </head>
  <body>
    {}
    <hr>
    {}
    <hr>
    {}
  </body>
</html>
'''

def parse_query(params):
    name = '未入力'
    email = '未入力'

    for param, value in params:
        if param == 'name':
            name = value
        elif param == 'email':
            email = value

    errors = []
    if name == '未入力':
        errors.append('メールアドレスの入力がありません。')
    if email == '未入力':
        errors.append('お名前の入力がありません。')

    return name, email, errors


def test_app(environ, start_response):

    start_response('200 OK', [('Content-Type','text/html')])

    # フォームから値を取得( GET )
    query = cgi.parse_qsl(environ.get('QUERY_STRING'))
    name, email, errors = parse_query(query)

    result = 'お名前:{}<br />'.format(name)
    result += 'メールアドレス: {}'.format(email)

    # 結果を表示
    return [html.format(
        'リクエストは {} です。'.format(environ.get('REQUEST_METHOD')),
        result, 
        '<br />'.join(errors)
    ).encode('UTF-8')]


# WSGIテストサーバーの作成
with make_server('', 8000, test_app) as httpd:

    # テストサーバーによる待ち受け
    print('Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...')
    httpd.serve_forever()

47行目のcgi.parse_qslの戻り値はリストで、内包される値は各パラメータを保持したタプルとなります。たとえば次のようなURLでアクセスした場合の戻り値は[(‘name’, ‘test_user’), (‘email’, ‘test_user@example.com’)]のような形となります。

POST

POSTリクエストの処理方法は下記の通りとなります。次の例はGETでアクセスしてきたときには入力フォームを、POSTでアクセスしてきたときには入力値を表示する形です。

import cgi
from wsgiref.simple_server import make_server


# 入力HTML文字列
input_html = '''
<!DOCTYPE html>
<html>
  <head>
    <title>CGI</title>
    <meta charset="UTF-8">
  </head>
  <body>
    <form method="POST" action="/">
      <input type="text" name="name">
      <input type="text" name="email">
      <input type="submit">
    </form>
  </body>
</html>
'''

# 結果HTML文字列
result_html = '''
<!DOCTYPE html>
<html>
  <head>
    <title>CGI</title>
    <meta charset="UTF-8">
  </head>
  <body>
    {}
    <hr>
    {}
    <hr>
    {}
  </body>
</html>
'''

def parse_query(query):
    name = '未入力'
    email = '未入力'

    for param, value in query:
        if param == b'name':
            name = value.decode('UTF-8')
        elif param == b'email':
            email = value.decode('UTF-8')

    errors = []
    if name == '未入力':
        errors.append('メールアドレスの入力がありません。')
    if email == '未入力':
        errors.append('お名前の入力がありません。')

    return name, email, errors

def test_app(environ, start_response):

    start_response('200 OK', [('Content-Type','text/html')])
    method = environ.get('REQUEST_METHOD')

    # フォームから値を取得
    if method == 'POST':
        wsgi_input = environ['wsgi.input']
        content_length = int(environ.get('CONTENT_LENGTH', 0))
        query = cgi.parse_qsl(wsgi_input.read(content_length))
        name, email, errors = parse_query(query)

        result = 'お名前:{}<br />'.format(name)
        result += 'メールアドレス: {}'.format(email)

        # 結果を表示
        return [result_html.format(
            'リクエストは {} です。'.format(method),
            result, 
            '<br />'.join(errors)
        ).encode('UTF-8')]

    return [input_html.encode('UTF-8')]

# WSGIテストサーバーの作成
with make_server('', 8000, test_app) as httpd:

    # テストサーバーによる待ち受け
    print('Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...')
    httpd.serve_forever()

cgi.parse_qslを用いるのはGETと変わりませんが、その過程が異なります。先に述べた通りGET/POSTで処理が分岐するため、次のURLへアクセスした時には入力フォームが表示されます。submitボタンを押すとPOSTアクセスとなるため、その入力値を取得・表示します。

またPOSTでは入力値がbytesで取得されます( [(b’name’, b’test_user’), (b’email’, b’test_user@example.com’)] のような形)。47行目、49行目でdecodeしてから値を格納している点に注意してください。

テストサーバーでの動作確認

先の例をmain.pyとして保存し、次のようなディレクトリ階層で配置するものとします。WSGIテストサーバーの処理はすでにソースコード内に記述してあるので、それを起動するだけです。

  • c:
    • python
      • main.py

次のコマンドを入力し、まずはc:/pythonへ移動します。

cd c:/python

次に簡易テストサーバーを起動します。

python main.py

待ち受け状態となったらウェブブラウザを開き次のURLを入力してください。あとに続く画像がPOSTのサンプルプログラムにおけるウェブブラウザでの表示例です。


何も入力せずに送信ボタンを押すと、次のような画面となります。入力値を取得できなかったので、お名前やメールアドレスが未入力となっているはずです。


最初の入力フォームへ戻り、値を入力してから送信ボタンを押すと次のようになります。POSTで値を取得できたので、その入力値が表示されます。また「〇〇の入力がありません。」というエラーメッセージがなくなっています。