TL; DR
POST
query = env['wsgi.input'].read(int(env.get('CONTENT_LENGTH', 0))).decode('utf-8')
GET
query = env.get('QUERY_STRING', '')
parse and split
# dictionary
form = urllib.parse.parse_qs(query)
# list
form = urllib.parse.parse_qsl(query)
経緯
フォームから送られたデータを扱うとき、CGI では cgi.FieldStorage() を取得していました。
import cgi
form = cgi.FieldStorage()
title = form.getfirst('title', 'Empty Title')
content = form.getfirst('content')
WSGI ではお作法が変って、クエリ文字列を一旦取得してから処理するのが定石のようです。
POST と GET ではやや取得の仕方が異なりますが、その後の処理が共通なのでまとめて記述したサンプルを載せます。
サンプルプログラム
# coding: utf-8
from urllib.parse import parse_qs
def application(env, res):
res('200 OK', [('Content-type', 'text/html; charset=utf-8')])
# Form
yield '<form method="get" accept-charset="UTF-8"><p><input type="text" name="get" value=""><input type="submit" value="GET"></form>'.encode('utf-8')
yield '<form method="post" accept-charset="UTF-8"><p><input type="text" name="post" value=""><input type="submit" value="POST"></form>'.encode('utf-8')
# Request method
method = env.get('REQUEST_METHOD')
yield '<p>Method: {}</p>'.format(method).encode('utf-8')
# Get query string
if method == 'POST':
wsgi_input = env['wsgi.input']
length = int(env.get('CONTENT_LENGTH', 0))
query = wsgi_input.read(length).decode('utf-8')
else:
query = env.get('QUERY_STRING', '')
yield '<p>Query: {}</p>'.format(query).encode('utf-8')
# Output form fields
form = parse_qs(query)
for k, v in form.items():
yield '<p>{} = {}</p>'.format(k, v).encode('utf-8')
簡単な解説
method = env.get('REQUEST_METHOD')
環境変数 REQUEST_METHOD で GET か POST なのかを判別します。
wsgi_input = env['wsgi.input']
length = int(env.get('CONTENT_LENGTH', 0))
query = wsgi_input.read(length).decode('utf-8')
POST での query の読み込みです。使い捨て変数だらけになるので一行でまとめても良いのですが、サンプルということでわざと分けています。
query = env.get('QUERY_STRING', '')
GET での query の読み込みです。第 2 引数は QUERY_STRING が存在しないときの戻り値です。
form = parse_qs(query)
for k, v in form.items():
yield '<p>{} = {}</p>'.format(k, v).encode('utf-8')
urllib.parse.parse_qs() は name=value&foo=bar の形式になっている query 文字列を辞書にして返します。qs は Query String の略でしょうか。一文字違いで urllib.parse.parse_qsl() もありますが、こちらは辞書ではなくペアのリストを返します。parse_qsl() を使って上記を書き換えると次のようになります(import も修正してください)。
form = parse_qsl(query)
for k, v in form:
yield '<p>{} = {}</p>'.format(k, v).encode('utf-8')