· 4分で読了

formタグとFormDataの活用

この記事は中国語から自動翻訳されたものです。翻訳によりニュアンスが失われている場合があります。

前回の記事では、僕たちは multipart/form-data のリクエスト形式と、それが解決しようとしている課題について紹介した。今回の記事では、実際の開発で直面する問題や活用方法について解説する。

具体的には、本記事ではフォームの活用に関する以下の内容を扱う:

  • <form/> タグの裏側で何が行われているか
  • JavaScriptにおけるFormDataの活用
  • FormDataと fetch の組み合わせ
  • JavaScriptでファイルアップロードを操作する方法

改めてformタグについて

HTMLのformタグには、実はブラウザが実装してくれている細かな処理がたくさんあり、開発者はそれを見落としがちだ。以下の例を見てみよう:

<form method="POST" action="/upload" enctype="multipart/form-data">
  <input type="text" name="name" />
  <input type="file"  name="file" />
  <button>
    Submit
  </button>
</form>

JavaScriptのコードが一切ない状態でも、Submitボタンを押せばブラウザが以下の処理を自動で行ってくれる:

  • input内のnameおよびfileフィールドをシリアライズする
  • POSTメソッドで Content-Type: multipart/form-data のHTTPリクエストを送信する
  • ファイルを読み込み、リクエスト内容に追加する(ファイルが存在する場合)

SPA(シングルページアプリケーション)やフロントエンドフレームワークがまだ流行っていなかった頃は、formフォームにデータを入力して送信し、別のページへリダイレクトするのが一般的な手法だった。しかし、入力するデータが増えたり、一部のエリアだけを更新したい(例えばコメント欄など)場合、毎回ページ全体を再読み込みするのはユーザー体験としてあまり良くない。そのため、AjaxでAPIを叩き、JavaScriptでデータを動的に更新する手法が徐々に広まっていった。

Desktop - 1

動的更新の手法は確かにユーザー体験を向上させたが、優れたフォーム設計を実現するには多くの細部を考慮する必要がある:

  • エラーハンドリング
  • 状態遷移
  • データの保持
  • アクセシビリティ(Accessibility)

多くのケースでは、どれか1つの要素でも疎かになると、ユーザーはむしろ単にページ全体を更新する通常のフォームタグで操作したほうがマシだと感じてしまう。管理画面のようなアプリケーションにおいては、<form> フォームによるページ全体の更新を採用することで多くの開発時間を削減できることが多く、ブラウザの組み込み機能に頼るほうがかえって安定して動作することさえある。

JavaScriptにおけるFormDataの活用

FormData は、開発者がkey/valueのような操作を扱いやすくするためのインターフェースを定義しており、最も一般的な用途はフォーム処理だ。FormData の宣言は次のように書ける:

const formData = new FormData()
//                key     value
formData.append('name', 'Kalan');

form要素を FormData に渡すと、フォーム内に入力された情報が自動的に FormData としてシリアライズされる:

<form id="form" enctype="multipart/form-data" action="/upload" method="POST">
  <input type="text" name="name" />
  <input type="file" name="file" />
  <button>Submit</button>
</form>

<script>
  const formData = new FormData(document.getElementById('form'));
  formData.get('name'); // 取得目前 input 的值
  formData.get('file'); // 取得目前的檔案
</script>

FormData 在 JavaScript 的應用

さらに、FormDataをfetchのbodyに設定すると、ブラウザが自動的に multipart/form-data の形式で送信してくれる:

const formData = new FormData();
formData.append('name', 'Kalan');
formData.append('file', new File(['Hello World'], 'file.txt', { type: 'text/plain' }))

fetch('/upload', {
  method: 'POST',
  body: formData
})

上記のJavaScriptコードを実行してNetworkリクエストを観察すると、Content-Typeを特に指定していなくても、ブラウザが自動的に multipart/form-data として送信してくれ、form dataのシリアライズもブラウザによって行われていることがわかる。

用 fetch 與 FormData 傳送 multipart form-data 請求

まとめ

この2つの記事を通じて、multipart/form-data の活用法と実際の実装方法を解説した。1本目の記事では、Content-Disposition の意味、boundaryの用途、そしてmultipart/form-dataリクエストの構造について解説した。2本目となる本記事では、実務においてformとFormDataをどのように活用できるか、そしてJavaScriptを通してFormDataの処理やファイルアップロードを行う方法を説明した。

サーバー側から見れば、Webページでのファイルアップロードという動作も1つのHTTPリクエストに過ぎない。そのため、サーバー側はヘッダーの情報や multipart/form-data で定義されたフォーマットに基づいてデータをパースして初めて、ファイル内容を正しく取得できる。通常、これらのパース処理はフレームワークによって隠蔽されているが、ここで僕が特に強調しておきたいのは、Web上でファイルを転送することに不思議な魔法などなく、裏側では依然としてHTTPリクエストに基づいているということだ。

関連記事

他のトピックを探索