旧記事名: (簡易メモ) JavaScript+FastAPI で FormData 送信時にハマったこと
問題
例えば、FastAPI に、
# import 等は省略
@app.post("/post")
def route_post(key1: str = Form(...), key2: str = Form(...)):
print(key1)
print(key2)
return
といったルートがあり、そこに JavaScript で以下のようにフォームデータを送信するとき、
var form = new FormData();
form.append("key1", "any_value1");
form.append("key2", "any_value2");
var xhr = new XMLHttpRequest();
xhr.open("POST", "/post");
- xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.send(form);
といった感じに書くと思います。
ここで、setRequestHeader("Content-Type", ...)
を入れてしまうと、400
エラーが返されてしまいます。
INFO: 127.0.0.1:46198 - "POST /post HTTP/1.1" 400 Bad Request
解法
自力でリクエストヘッダを設定せず、自動にさせると正常に動きます。
原因
[2023/01/21 追記]
そもそも multipart/form-data
というデータ型は、複数の種類のデータを結合して、1つにまとめたものです。
content-type: multipart/form-data; boundary=----WebKitFormBoundaryXfObUzJva7ymK2dx
------WebKitFormBoundaryXfObUzJva7ymK2dx
Content-Disposition: form-data; name="key1"
any_value1
------WebKitFormBoundaryXfObUzJva7ymK2dx
Content-Disposition: form-data; name="key2"
any_value2
------WebKitFormBoundaryXfObUzJva7ymK2dx--
HTTP リクエストで送るとき、Content-Type
ヘッダに boundary
という項目が必須になります。boundary
は、データの区切りを示す文字列であるため、必須の項目なのです。
手動で setRequestHeader
を書いてしまうと、この boundary
が消えてしまうので、400エラーが発生してしまう、というわけです。
ちなみに、MDN Web Docs に、ご丁寧にその警告がありました。ドキュメント読み、大事、ゼッタイ。
警告: FormData を使用して、
XMLHttpRequest
またはFetch_API
を使用して、multipart/form-data
の Content-Type で POST リクエストを送信する場合 (Files や Blob をサーバーにアップロードする場合など)、リクエストのContent-Type
ヘッダーを明示的に設定しないでください。そうすると、ブラウザーがリクエスト本文のフォームフィールドの区切りに使用する境界の表現で Content-Type ヘッダーを設定することができなくなります。
[2022/3/23 追記]
編集リクエスト頂き、ありがとうございました。
「メモ タグを追加してみました by @Tetsu_Oikawa」
[2023/01/21 追記]
原因がちゃんと分かったので、簡易メモから昇進させました。