2026年10月31日、Pythonでフォームのデータを読み取るライブラリpython-multipartの0.0.33が公開されました。FastAPIやStarletteで、HTMLのフォームを受け取るときに使われているライブラリです。
今回の目玉は、送られてくる項目の数と、1つの項目の大きさに、上限を設けられるようになったことです。あわせて、Python 3.10のサポートを終え、3.15に対応しました。
なぜ、わざわざ上限が必要なのでしょうか。今回は、0.0.32と0.0.33で同じコードを動かしながら、上限の意味と、FastAPIでの扱いを見ていきます。
まずはpython-multipartとはどんなものか¶
最初に、python-multipartがどんなライブラリなのかを確認しておきましょう。ブラウザのフォームから送られるデータは、主に2つの形式のどちらかで届きます。
| 形式 | 中身の例 | よく使う場面 |
|---|---|---|
| application/x-www-form-urlencoded | name=taro&age=20 |
文字だけのふつうのフォーム |
| multipart/form-data | 区切り線で項目を分けた形式 | ファイルのアップロードを含むフォーム |
python-multipartは、この2つの形式を読み取って、項目ごとに取り出すためのライブラリです。名前にmultipartとありますが、1つ目のURLエンコードの形式も扱えます。
FastAPIとの関係¶
FastAPIでForm()を使うには、python-multipartを入れておく必要があります。手元の環境でも、FastAPI 0.162.0と一緒に、Starlette 1.10.0とpython-multipart 0.0.33が入っていました。
フォームの扱いが最近どう変わったのかは、こちらで紹介しています。【関連記事】FastAPIが3日で0.150へ。HTMLフォームの扱いが変わった
0.0.33で何が変わったのかを整理しよう¶
続いて、0.0.33の主な変更を表にまとめます。内容は、python-multipartの公式リポジトリにある変更履歴CHANGELOG.mdにもとづいています。
| 分類 | 主な変更 |
|---|---|
| Pythonの対応範囲 | 3.10のサポートを終了し、3.15に対応 |
| 新機能 | URLエンコードのフォームで、項目の数と大きさの上限を設定できるように |
| 不具合の修正 | Content-Transfer-Encodingの解読を、項目を渡す前に終えるように |
| 不具合の修正 | 名前のないアップロードや、文字列で指定した保存先の扱いを修正 |
| 速度 | 区切り線の照合やコールバックの呼び出しを高速化 |
PyPIの記録によると、0.0.33が必要とするPythonは3.11以上です。ひとつ前の0.0.32は、2026年6月4日に公開されていました。
主要なライブラリがPython 3.10を外していく流れは、こちらでもまとめています。【関連記事】Python 3.10のサポート終了から2週間、主要ライブラリの対応状況
なぜ上限が必要なのか¶
新機能の話に入る前に、上限がなぜ大事なのかを考えてみましょう。Webアプリは、誰から送られてくるかわからないデータを受け取ります。
もし、項目が何十万個も並んだフォームや、1つの項目に何百メガバイトもの文字を詰め込んだフォームが送られてきたらどうでしょうか。読み取るだけでメモリや処理の時間を使い果たし、ほかの利用者の操作まで遅くなってしまいます。
サービス妨害という攻撃¶
このように、大量のデータや重い処理を押し付けてサービスを止めようとする攻撃を、サービス妨害、英語ではDoS(Denial of Service)と呼びます。項目の数や大きさに上限を設けるのは、DoSを防ぐ基本的な守りの1つです。
上限があれば、想定を超えたデータは早い段階で断れます。全部を読み終えてから判断するより、ずっと少ない負担で済むわけです。
0.0.32と0.0.33で上限を試してみた¶
では、実際に新しい上限を試してみましょう。python-multipartのFormParserに、configで上限を渡します。
項目の数の上限¶
まずは、項目の数の上限です。MAX_FIELDSを3にして、4つの項目が入ったデータを読ませてみました。
from python_multipart.exceptions import FormParserError
from python_multipart.multipart import FormParser
fields = []
parser = FormParser(
"application/x-www-form-urlencoded",
on_field=lambda f: fields.append((f.field_name, f.value)),
on_file=None,
config={"MAX_FIELDS": 3},
)
try:
parser.write(b"a=1&b=2&c=3&d=4")
parser.finalize()
except FormParserError as e:
print("FormParserError:", e)
print(len(fields), "件:", fields)
0.0.32と0.0.33を、それぞれ新しい仮想環境に入れ、手元のPython 3.11で実行した結果です。
python-multipart 0.0.32
4 件: [(b'a', b'1'), (b'b', b'2'), (b'c', b'3'), (b'd', b'4')]
python-multipart 0.0.33
FormParserError: Too many fields. Maximum number of fields is 3.
3 件: [(b'a', b'1'), (b'b', b'2'), (b'c', b'3')]
0.0.32では、MAX_FIELDSという設定はまだなかったので、4つすべてが読み取られました。0.0.33では、4つ目に入ったところで、項目が多すぎるというエラーで止まっています。
1つの項目の大きさの上限¶
続いて、MAX_FIELD_SIZEを20バイトにして、100文字のコメントを含むデータを読ませました。コードは先ほどとほぼ同じなので、違う部分だけを載せます。
config={"MAX_FIELD_SIZE": 20}
parser.write(b"name=taro&comment=" + b"x" * 100)
結果は次のとおりです。
| 版 | 結果 |
|---|---|
| 0.0.32 | nameとcommentの2つとも読み取られた |
| 0.0.33 | Field exceeded maximum size of 20 bytes.というエラーで止まり、読めたのはnameだけ |
変更履歴によると、これらの上限は自分で指定したときだけ働く、オプトインの仕組みです。実際に既定の設定を見ると、MAX_FIELDSもMAX_FIELD_SIZEも、上限なしを表す無限大になっていました。
FastAPIでは、すでに上限がある¶
ここで気になるのが、FastAPIを使っている人への影響ですよね。調べてみると、少し意外なことがわかりました。
インストールされたStarlette 1.10.0のコードを見ると、Starletteはフォームを読むときに、自分で項目の数と大きさを数えていました。既定の上限は、項目が1,000個、1つの項目が1MBです。
1,001個の項目を送ってみた¶
実際に、FastAPIのアプリに、1,000個と1,001個の項目を持つフォームを送ってみました。
from fastapi import FastAPI, Request
from fastapi.testclient import TestClient
app = FastAPI()
@app.post("/survey")
async def survey(request: Request):
form = await request.form()
return {"fields": len(form)}
client = TestClient(app)
for n in (1000, 1001):
body = "&".join(f"q{i}=yes" for i in range(n))
res = client.post(
"/survey",
content=body,
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
print(n, res.status_code, res.text)
実行した結果です。
1000 200 {"fields":1000}
1001 400 {"detail":"Too many fields. Maximum number of fields is 1000."}
1,000個までは受け付けられ、1,001個目で400のエラーになりました。FastAPIやStarletteを使っている場合は、今回の新機能を使わなくても、すでに既定の上限で守られていることになります。
上限を自分で変えるには¶
もっと厳しくしたい場合は、await request.form(max_fields=10)のように、上限を指定できます。手元で11個の項目を送ると、Too many fields. Maximum number of fields is 10.という400のエラーになりました。
Starletteの最近の変更については、こちらで紹介しています。【関連記事】Starlette 1.9と1.10がリリース
では、誰にとって嬉しい変更なのか¶
ここまでをまとめると、今回の新機能が直接役立つのは、python-multipartを直接使っている人です。立場ごとに、表にまとめます。
| 立場 | 今回の変更との関係 |
|---|---|
| FastAPIやStarletteでフォームを受け取る | Starletteの既定の上限がすでにある。必要ならrequest.form()で調整 |
| python-multipartのFormParserを直接使う | 新しいMAX_FIELDSとMAX_FIELD_SIZEで、上限を設けられるようになった |
| 自分でWebフレームワークやツールを作る | 上限を指定し忘れると無制限のままなので、明示しておく |
既定が無制限のままなのは、これまでの動きを変えないためだと考えられます。直接使っている方は、上げたうえで、自分のアプリに合った上限を指定しておきましょう。
FastAPIそのものの使い方は、こちらで紹介しています。【関連記事】PythonのFastAPIとは?
上げる前にやっておきたいこと¶
最後に、python-multipartを0.0.33へ上げる前に確かめておきたいことを整理します。
| 順番 | 確認すること |
|---|---|
| 1 | Python 3.11以上を使っているか |
| 2 | FormParserを直接使っているなら、MAX_FIELDSとMAX_FIELD_SIZEを決める |
| 3 | FastAPIで大きなフォームを受け取るなら、Starletteの上限に収まるか確かめる |
| 4 | 使う版を、requirements.txtなどで固定しているか |
私は10年ほどエンジニアとして開発に関わってきましたが、アンケートの管理画面で、想定の何十倍もの項目を持つ不正なリクエストが届き、サーバーが一時的に重くなったことがあります。それ以来、受け取るデータには、必ず上限を決めておくようにしています。
上限は、厳しすぎると正しい利用者まで困らせてしまいます。自分のフォームの項目数や、入力される文字の量を確かめたうえで、余裕を持った値を決めるのがおすすめです。
まとめ¶
2026年10月31日、python-multipart 0.0.33が公開されました。URLエンコードのフォームで、項目の数と1つの項目の大きさに上限を設けられるようになり、Python 3.10のサポートも終わっています。
FastAPIやStarletteでは、すでに既定の上限があります。直接python-multipartを使っている方は、この機会に上限を明示しておきましょう。
ここまでお読みいただきありがとうございました。