Pythonの`requests`でファイル送信するときにヘッダーにmultipart/form-dataを直接指定してはいけない
DA事業本部の横山です。
Pythonのrequests
を用いて、multipart/form-data
のデータを送信する際にヘッダーに指定すると失敗してしまいます。
知らずにはまったので、確認方法を含めて共有のために記載しておきます。
前提条件
本記事で利用している各ライブラリ等のバージョンは以下になります。
Python
:3.8.13
requests
:2.29.0
概要
requests
で、ファイル情報をPOSTする- リクエストヘッダへ
multipart/form-data
の有無でリクエスト内容の違いを確認する
ファイルを requests でPOSTする
以下のようなソースを用意しました。
import http.client as http_client import requests http_client.HTTPConnection.debuglevel = 1 host = "localhost:3000" endpoint = f"http://{host}/hello" headers = { "Content-Type": "multipart/form-data", } params = { "id": 1, } target_file = open("/tmp/hello.txt", "r") files = {"file": (target_file.name, target_file.read())} response = requests.post(url=endpoint, data=params, files=files, headers=headers) response.raise_for_status() print(response.json())
ポイントとしては、以下のコードを記載することでrequestsの詳細なログを確認することができます。
import http.client as http_client http_client.HTTPConnection.debuglevel = 1
以下のヘッダー指定の部分を入れるかコメントアウトを行ってリクエスト内容の違いについて確認していきます。
headers = { "Content-Type": "multipart/form-data", }
リクエスト内容の違い
ソースコード上で、"Content-Type": "multipart/form-data"
の指定をコメントアウトした場合、
send: b'POST /hello HTTP/1.1 Host: localhost:3000 User-Agent: python-requests/2.31.0 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Content-Length: 276 Content-Type: multipart/form-data; boundary=275c6206e4ffc5bc98092f0260014599 ' send: b'--275c6206e4ffc5bc98092f0260014599 Content-Disposition: form-data; name="id" 1 --275c6206e4ffc5bc98092f0260014599 Content-Disposition: form-data; name="file"; filename="/home/yokoyama-takato/work/abaa/test/blog/hello.txt" hello --275c6206e4ffc5bc98092f0260014599-- '
ソースコード上で、"Content-Type": "multipart/form-data"
の指定を行った場合、
send: b'POST /hello HTTP/1.1 Host: localhost:3000 User-Agent: python-requests/2.31.0 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Content-Type: multipart/form-data Content-Length: 276 ' send: b'--4a5d9783d6c2bc6e5c3b4110b1ab5005 Content-Disposition: form-data; name="id" 1 --4a5d9783d6c2bc6e5c3b4110b1ab5005 Content-Disposition: form-data; name="file"; filename="/home/yokoyama-takato/work/abaa/test/blog/hello.txt" hello --4a5d9783d6c2bc6e5c3b4110b1ab5005-- '
二つを比較すると以下のboundary(境界)の値以外に以下の部分が異なっています。
ヘッダー指定なし:Content-Type: multipart/form-data; boundary=275c6206e4ffc5bc98092f0260014599 ヘッダー指定あり:Content-Type: multipart/form-data
ヘッダーに明示的に"Content-Type": "multipart/form-data"
の指定を行った場合は、boundaryの値が正しく付与できていないことがわかります。
このため、requests
を利用する際に"Content-Type": "multipart/form-data"
を直接指定することは避けましょう。
"Content-Type": "multipart/form-data"
詳細については以下のリンクを参照ください。
おわりに
リクエスト内容眺めても、ヘッダー部にboundaryが付与されていないことに気が付くのは難しいと思います。 私はプロジェクトメンバに指定いただいて解決したので、おなじようにハマる方が1人でも減ってくれたらうれしいです。
以上になります。この記事がどなたかの助けになれば幸いです。