LoginSignup
2
0

More than 1 year has passed since last update.

JavaScript で FormData 送信時、Content-Type を自分で書いてはいけない

Last updated at Posted at 2022-03-22

旧記事名: (簡易メモ) 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つにまとめたものです。

Header の一部
content-type: multipart/form-data; boundary=----WebKitFormBoundaryXfObUzJva7ymK2dx
body 全文
------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 追記]
原因がちゃんと分かったので、簡易メモから昇進させました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0