【ReactNative開発】FormDataとそれに関わる技術(fetch,XHR,multipart/form-data) を理解する

こんばんは。今週はReact Nativeにおける画像の扱いと戦っております。React Nativeのアプリからサーバサイドへ画像をアップロードしたいのですが、どうにもうまくいかない・・

トラブルシューティングしようにも、このあたりの技術に対する理解がなさすぎて辛くなってきたので、腰を据えて、勉強しようと思った次第です・・・

自分の抱えている問題を解決するために調べたことを残していっているだけなので、網羅的な解説にはなっていない点、ご容赦ください・・・

それでは参ります。

Contents

FormDataの概要

https://developer.mozilla.org/ja/docs/Web/API/FormData/Using_FormData_Objects

FormData オブジェクトは、XMLHttpRequest を使用して送信するためのキーと値のペアのセットを収集可能にします。本来はフォームデータの送信に使用することを想定していましたが、キーのついたデータを伝送するためにフォームとは独立して使用することもできます。伝送されるデータは、フォームのエンコードタイプが multipart/form-data に設定されている場合に、submit() メソッドで送信する際に使用するデータと同じ形式です。

テキストデータだけでなく、FileやBlobをformdataとして送信することも可能。

data.append("myfile", myBlob, "filename.txt");

ちなみに、formdataで画像などのBlobを送る場合、上記のような送り方以外にも、こんな方式もあるみたい。

画像のBlob自体をセットする代わりに、画像のURI、ファイル名、MIMEタイプを設定を設定する方法のようです。私も、React Native+Expoで開発していて、どうにも上の方法では画像のアップロードが行えなかった(Android Emulatorの問題・・?)ので、他の方法を探していたところこちらの方法に辿り着きました。

  let formData = new FormData();
  // Assume "photo" is the name of the form field the server expects
  formData.append('photo', { uri: localUri, name: filename, type });

https://stackoverflow.com/questions/42521679/how-can-i-upload-a-photo-with-expo

なんだこの送り方は・・MozillaのformData.append()の仕様書に戻ってみる。

https://developer.mozilla.org/ja/docs/Web/API/FormData/append

Syntaxのところに説明がありますが、formDataのappendは、以下の形式と定義されているよう。filenameは省略可能。疑問はここのvalueのところですね。以下の説明があった。

formData.append(name, value);
formData.append(name, value, filename);

The field’s value. This can be a USVString or Blob (including subclasses such as File). If none of these are specified the value is converted to a string.

USVStringかBlobもOK、と書いていますね。が、この説明からも、先程の形式で送れる理由がわからない・・・。そのStack OverflowのDiscussionで、同じ疑問を投げかけている人がいますね・・

How did it work? Local URI shouldn't be accessible on the backend . right? 

いろいろ調べてみましたが結局この原理は分からず・・・誰か知ってる人いたら教えてください・・

XMLHttpRequestとは

https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest

XMLHttpRequest (XHR) オブジェクトは、サーバーと対話するために使用されます。ページ全体を更新する必要なしに、データを受け取ることができます。これでユーザーの作業を中断させることなく、ウェブページの一部を更新することができます。 XMLHttpRequest は AJAX プログラミングで頻繁に使用されます。

XMLHttpRequest という名前ではあるものの、 XML だけでなくあらゆる種類のデータを受け取るために使用することができます。

公式Docより

ん、サーバと対話するために使用される?どういうことだ?上の図をみてもさっぱりなんのとこか分からない・・笑

Wikipediaには、もう少し別の説明と、歴史について記載がありました。マイクロソフトが利用し始めたのがきっかけだったようですね。

https://ja.wikipedia.org/wiki/XMLHttpRequest

XMLHttpRequest (XHR) は、JavaScriptなどのウェブブラウザ搭載のスクリプト言語サーバとのHTTP通信を行うための、組み込みオブジェクトAPI)である。

すでに読み込んだページからさらにHTTPリクエストを発することができ、ページ遷移することなしにデータを送受信できるAjaxの基幹技術である。

XMLHttpRequestを利用したWebアプリケーションは非常に多く存在し、例として、Google マップFacebookなどが挙げられる。

Wikipediaより

XMLHttpRequestはどういう場合に使われる?その答えはこちらに分かりやすく説明されておりました。

https://ja.javascript.info/xmlhttprequest

ここをみると、現在はfetch APIが主流というようなことが書いていました。ん、XMLHttpRequestの後継がFetchなの?ということで調べてみると、その点が分かりやすくまとめられたQiitaの記事を発見しました。ものすごいLGTM数です。そして分かりやすい。

https://qiita.com/uhyo/items/91649e260165b35fecd7

余談ですが、一体どれだけ技術に触れればこんな深く語れるようになるんだろう、と思って書いた方のGithubのContribution Historyを見てみると、ものすごいことになっていました(土日も関係なくずっとContributionされている・・・)

こういうレベルになると、ここまで語れるのですね・・・(絶望と尊敬)

一つ前の記事でも語られていましたが、現在においては、新しく開発する場合、fetchで実現できないことを実現したい場合を除いては、fetchを使う、という整理で良さそうだと理解しました。

話をformdataに戻すと、”XMLHttpRequest を使用して送信するためのキーと値のペアのセットを収集可能にします。“と書いていますが、fetch APIを使っている人は、XHRをfetchと読み替えて解釈すれば良さそうです。

Multipart/Form-Dataとは

こちらの説明がとても分かりやすかったです。Boundaryという文字列で複数のデータを区切っているのですね。

https://www.yoheim.net/blog.php?q=20171201

一応、Mozillaの公式Docも。

https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/POST

FormDataとしてデータを送信すると、multipart/form-dataとしてデータが送信されるのですね。

なるほど、ここまで事前知識を得ると、MozillaのFormDataの説明にあった以下の注意事項が理解できました。Fetch APIやXHRでformdataを送る際、明示的にContent-Typeを”multipart/form-data”として設定するような実装をしてしまうと、Boundary情報を埋め込めなくなってしまうからやめてね、ということなのですかね。

FormData を使用して、XMLHttpRequest または Fetch_API を使用して、 multipart/form-data の Content-Type で POST リクエストを送信する場合 (Files や Blob をサーバーにアップロードする場合など)、リクエストの Content-Type ヘッダーを明示的に設定しないでください。そうすると、ブラウザーがリクエスト本文のフォームフィールドの区切りに使用する境界の表現で Content-Type ヘッダーを設定することができなくなります。

まだもう少し足していくことになりそうですが、力尽きたので今日はここまで・・・

おしまい

この記事を気に入っていただけたらシェアをお願いします!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US
Yuu113
初めまして。ゆうたろうと申します。 兵庫県出身、東京でシステムエンジニアをしております。現在は主にデータ分析、機械学習を活用してビジネスモデリングに取り組んでいます。 日々学んだことや経験したことを整理していきたいと思い、ブログを始めました。旅行、カメラ、IT技術、江戸文化が大好きですので、これらについても記事にしていきたいと思っています。