概要
社内の業務で、JSONで受け取ったリクエストをmultipart/form-dataとして扱ってAPI送信するみたいなことがあって、その際にそもそもmultipart/form-dataってなんぞ? ってなったので、備忘録もかねて記事にしてみます。
そもそもMultipart/form-dataとは何か。
IT用語辞典によると、HTMLフォームによるデータ送信を意味するMIMEタイプとのこと。
要は<form>タグの中身をリクエストとして送りつける際に使われてるMIMEタイプってことみたいですね。
見慣れないタイプだけど、多分実は裏でめっちゃ多用してるContentTypeなんだろうなっていうのが個人的な感想です。
・multipartの中身を見てみる.
POST /test.html HTTP/1.1
Host: example.org
Content-Type: multipart/form-data;boundary="boundary"
--boundary
Content-Disposition: form-data; name="field1"
value1
--boundary
Content-Disposition: form-data; name="field2"; filename="example.txt"
value2
--boundary--
mdnのドキュメントによるとこんな感じ。。。
実質ContentTypeが要素ごとに設定できる感じのご様子です。
身構えてたよりは記述方法自体は分かりやすそうですね。
・boundaryについて
今回詰まったのが、このboundaryに関してがメインなので、簡単にこの説明しておきます。
上のサンプル見てもらってもわかるかなとは思うんですが、
boundary自体が区切り文字になっていて、各要素を--boundary
の形で区切ることで、そこから先は次の要素という意思表示になります。
ちなみにこのboundaryですが、なんの文字列使ってもいいみたいです、ボディ内の文字列と、ヘッダー部分が一致さえしていれば問題ないとのこと。(このへん詳しくは他の記事で書かれたりしてたので、特に言及はしないです。)
本題 迷いやすい(気がする)ポイント
で、これを試しに書いてみた時に??ってなったので、今回はそこのお話です。
・ヘッダーに--は必要なのか
1つ目の迷いポイントがここです。
いろいろと参考サイト練り歩いてたんですが、個人ブログとかQiitaとかだと、
header部分のコンテントタイプの書き方がサイトさんによってかなり違いがあって、迷ってしまいました。
Content-Type: multipart/form-data;boundary="boundary"
この部分なんですが、
boundary = --[boundary文字列]
って書いている記事もあれば、
boundary=[boundary文字列]
の記事もあるし、
挙句の果てには
boundary = -------------------[bounday文字列]
みたいになっていて、もうどこからが区切り文字かわからないパターンも有る。
要はboundaryの文字列の前に--っているの? っていうお話です。
結論から言うと ヘッダー部分に記載するboundaryはboundary = [boundary文字列]
が正解です。
ちなみに最後の「---------------」みたいなパターンは、
ポストマンでMultipart/form-data
使ってリクエスト送ったときにはこの形式になったので、おそらくそことかから参考コード持ってこられたのかなと思います。
試しにSpringBootでリクエストの受け口作って両方のパターンで送ってみたんですが、baundary = hogehogeの場合だけ正しく受け取れました。
どこかのサイト参考に作って動かない場合はこの辺りも見ていただけるといいのかなと思います。
・ヘッダーとボディで異なるポイントも注意
boundary周りの書き方でもう一点。
ドキュメントだと
Content-Type: multipart/form-data;boundary="boundary"
こう書いてなるので、なるほど、boundaryを文字列として引数に渡すんだーとか思ってたら違いました。
仮にboundaryが[hogehoge]って文字列だとすると、
Content-Type: multipart/form-data;boundary=hogehoge
と言う感じで、ダブルクォートで囲ったりせずに、設定する必要があります。
で、それならbodyのフォーム名も?と思うとそうではなく、各フォーム項目の方は
Content-Disposition: form-data; name="field1"
この感じ(mdnの記載通り)で、name="フォーム名"の形で、フォーム名をダブルクォートで囲う必要があるみたいです。
僕自身は無意識にヘッダーだけ外していて、うまく行っていたんですが、
これサンプルじっくり見た人ほど沼りそうな内容だなぁと思ったので、ついでに書いておきます。
後の自分もミスりそうなポイントだしね。。。
最後に
というわけで、ContentTypeのMultipart/form-dataに関してでした。
正直初めて記事書くので、見にくい、わかりにくい等々 色々あると思うんですが、ただの個人的なアウトプットの訓練なので、生暖かく見てくれると嬉しいです。
これを機にリクエストのContentType一覧形式で把握しておくのもいいかなと思ったので、また記事書くかもしれないです。