FormData によるフォームタグの適用

作成者:カランカラン
💡

質問やフィードバックがありましたら、フォームからお願いします

本文は台湾華語で、ChatGPT で翻訳している記事なので、不確かな部分や間違いがあるかもしれません。ご了承ください

前回の記事では、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フィールドをシリアライズする
  • Content-Type: multipart/form-dataのHTTPリクエストをPOSTメソッドで送信する
  • ファイルを読み込み、リクエストの内容に追加する(ファイルが存在する場合)

シングルページアプリケーションやフロントエンドフレームワークが普及する前は、フォームにデータを入力して送信し、その後別のページにリダイレクトするのが一般的な方法でした。しかし、入力するデータが増えたり、一部の領域だけを更新する必要がある場合(例えばコメントなど)、毎回全ページを更新することはユーザーにとってあまり良い体験ではないため、次第にAJAXを介してAPIを叩き、JavaScriptでデータを動的に更新する方法が発展しました。

Desktop - 1

動的更新の方法は確かにユーザー体験を改善しましたが、良いフォームデザインを実現するには多くの詳細に配慮する必要があります:

  • エラーハンドリング
  • 状態遷移
  • データ保存
  • アクセシビリティ

多くの場合、一つの環境がうまくいかないと、ユーザーはむしろシンプルな全ページ更新のフォームタグを使いたがります。特にバックエンドアプリケーションの場合、<form>タグを使用して全ページ更新を行うことで、開発時間を大幅に節約でき、ブラウザの内蔵メカニズムを利用することで、より安定して動作することが多いです。

FormDataのJavaScriptにおける応用

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リクエストを送信

まとめ

この二つの記事では、multipart/form-dataの応用と実際の使用方法について説明しました。第一の記事では、Content-Dispositionの意味、boundaryの用途、そしてmultipart/form-dataのリクエストがどのように構築されるかについて説明しました。第二の記事では、実務においてフォームとFormDataをどのように使用し、JavaScriptを介してFormDataの処理とファイルアップロードを行うかについて説明しました。

サーバーサイドにとって、ウェブ上でファイルアップロードを行うことも一つのHTTPリクエストであるため、サーバーはヘッダー内の情報とmultipart/form-dataで定義された形式に基づいてデータを解析する必要があります。そうしないと、正しくファイルの内容を取得することができません。通常、これらの解析はフレームワークによって処理されていますが、ここで特に強調したいのは、ウェブ上でファイルをアップロードすることには特別な魔法はなく、その背後にはHTTPリクエストが基盤となっているということです。

この記事が役に立ったと思ったら、下のリンクからコーヒーを奢ってくれると嬉しいです ☕ 私の普通の一日が輝かしいものになります ✨

Buy me a coffee