コンテンツにスキップ

HTMLフォームの作成

Last reviewed: about 2 years ago

このチュートリアルでは、プレーンなHTMLとCSSを使用してシンプルな<form>を作成し、それをCloudflare Pagesにデプロイします。その過程で、いくつかのHTMLフォーム属性について学び、Worker内で送信されたデータを収集する方法を学びます。

このチュートリアルでは、Cloudflare PagesとそのWorkers統合を多く使用します。プラットフォームに慣れるために、Get started guideガイドを参照してください。

概要

ウェブ上では、フォームはユーザーとウェブドキュメントとの一般的なインタラクションのポイントです。ユーザーがデータを入力し、一般的にはそのデータをサーバーに送信することを可能にします。フォームは、テキストフィールド、ドロップダウン、チェックボックスなど、少なくとも1つのフォーム入力で構成されています。

各入力には名前を付ける必要があります。これはname属性を使用して、サーバーに受信されたときに入力の値に識別可能な名前を持たせるためです。さらに、HTML5の進展により、フォーム要素は自動フォーム検証にオプトインするための追加属性を宣言できます。利用可能な検証は入力タイプによって異なります。たとえば、メールを受け付けるテキスト入力(type=emailを介して)は、値が有効なメールアドレスのように見えることを確認できます。数値入力(type=numberを介して)は整数または小数値(許可されている場合)のみを受け入れ、一般的なテキスト入力はカスタムpatternを定義できます。ただし、すべての入力は、値がrequiredであるかどうかを宣言できます。

以下は、いくつかの入力とその検証ルールが定義されたHTML5フォームの例です:

<form method="POST" action="/api/submit">
<input type="text" name="fullname" pattern="[A-Za-z]+" required />
<input type="email" name="email" required />
<input type="number" name="age" min="18" required />
<button type="submit">送信</button>
</form>

HTML5フォームに検証ルールが定義されている場合、ブラウザはユーザーがフォームを送信しようとする際に自動的にすべてのルールをチェックします。エラーがある場合、送信は防止され、ブラウザはユーザーに修正のためのエラーメッセージを表示します。<form>は、未解決の検証エラーがない場合にのみ、データを/submitエンドポイントにPOSTします。このプロセス全体はHTML5にネイティブであり、適切なフォームと入力属性が存在するだけで済みます — JavaScriptは必要ありません。

フォーム要素には、<label>要素を関連付けることもでき、各入力を明確に説明できます。これは視覚的な明瞭さに優れていますが、HTMLマークアップがより明確に定義されるため、よりアクセシブルなユーザー体験を提供します。支援技術はこれから直接恩恵を受けます。たとえば、スクリーンリーダーはどの<input>がフォーカスされているかを発表できます。また、<label>がクリックされると、その関連付けられたフォーム入力がフォーカスされ、入力のアクティベーションエリアが広がります。

これを有効にするには、各入力のために<label>要素を作成し、各<input>要素にユニークなid属性値を割り当てる必要があります。<label>は、関連付けられた入力のユニークなid値を反映するfor属性も持っている必要があります。前のスニペットを修正すると、次のようになります:

<form method="POST" action="/api/submit">
<label for="i-fullname">フルネーム</label>
<input
id="i-fullname"
type="text"
name="fullname"
pattern="[A-Za-z]+"
required
/>
<label for="i-email">メールアドレス</label>
<input id="i-email" type="email" name="email" required />
<label for="i-age">あなたの年齢</label>
<input id="i-age" type="number" name="age" min="18" required />
<button type="submit">送信</button>
</form>

この<form>が有効なデータで送信されると、そのデータ内容はサーバーに送信されます。このデータがどのように、どこに送信されるかをカスタマイズするには、フォーム自体に属性を宣言する必要があります。これらの詳細を提供しない場合、<form>は現在のURLアドレスにデータをGETしますが、これは望ましい動作ではありません。これを修正するには、少なくともターゲットURLアドレスを持つaction属性を定義する必要がありますが、methodを宣言することも推奨されます。たとえデフォルトのGET値を再宣言する場合でも。

デフォルトでは、HTMLフォームはその内容をapplication/x-www-form-urlencoded MIMEタイプで送信します。この値は、受信サーバーがデータ内容を解析する方法を決定するために読み取る必要があるContent-Type HTTPヘッダーに反映されます。MIMEタイプは、enctype属性を通じてカスタマイズできます。たとえば、ファイルを受け入れるためには(type=fileを介して)、enctypemultipart/form-data値に変更する必要があります:

<form method="POST" action="/api/submit" enctype="multipart/form-data">
<label for="i-fullname">フルネーム</label>
<input
id="i-fullname"
type="text"
name="fullname"
pattern="[A-Za-z]+"
required
/>
<label for="i-email">メールアドレス</label>
<input id="i-email" type="email" name="email" required />
<label for="i-age">あなたの年齢</label>
<input id="i-age" type="number" name="age" min="18" required />
<label for="i-avatar">プロフィール写真</label>
<input id="i-avatar" type="file" name="avatar" required />
<button type="submit">送信</button>
</form>

enctypeが変更されたため、ブラウザはサーバーにデータを送信する方法も変更します。Content-Type HTTPヘッダーは新しいアプローチを反映し、HTTPリクエストのボディは新しいMIMEタイプに準拠します。受信サーバーは新しい形式に対応し、リクエスト解析方法を調整する必要があります。

ライブ例

このチュートリアルの残りの部分では、Pages上でHTMLフォームを構築し、フォーム送信を受信して解析するWorkerを作成します。

セットアップ

まず、新しいGitHubリポジトリを作成します。次に、マシン上に新しいローカルディレクトリを作成し、gitを初期化し、GitHubの場所をリモート先として接続します:

Terminal window
# 新しいディレクトリを作成
mkdir new-project
# 新しいディレクトリに入る
cd new-project
# gitを初期化
git init
# リモートを接続
git remote add origin git@github.com:<username>/<repo>.git
# デフォルトのブランチ名を変更
git branch -M main

これで、作成したnew-projectディレクトリで作業を開始できます。

マークアップ

この例のフォームは非常にシンプルです。複数の値を選択するためのチェックボックスを含むさまざまな入力タイプの配列が含まれています。また、フォームには検証が含まれていないため、空の値や欠落した値がサーバーでどのように解釈されるかを見ることができます。

この例プロジェクトではプレーンなHTMLのみを使用します。お好みのJavaScriptフレームワークを使用できますが、シンプルさと親しみやすさのために生の言語が選ばれています — すべてのフレームワークは、同様の結果を抽象化または生成しています。

プロジェクトディレクトリにpublic/index.htmlを作成します。すべてのフロントエンドアセットはこのpublicディレクトリ内に存在し、このindex.htmlファイルがウェブサイトのホームページとして機能します。

次の内容をpublic/index.htmlファイルにコピーして貼り付けます:

<html lang="ja">
<head>
<meta charset="utf8" />
<title>フォームデモ</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
</head>
<body>
<form method="POST" action="/api/submit">
<div class="input">
<label for="name">フルネーム</label>
<input id="name" name="name" type="text" />
</div>
<div class="input">
<label for="email">メールアドレス</label>
<input id="email" name="email" type="email" />
</div>
<div class="input">
<label for="referers">どのように私たちを知りましたか?</label>
<select id="referers" name="referers">
<option hidden disabled selected value></option>
<option value="Facebook">Facebook</option>
<option value="Twitter">Twitter</option>
<option value="Google">Google</option>
<option value="Bing">Bing</option>
<option value="Friends">友人</option>
</select>
</div>
<div class="checklist">
<label>あなたの好きな映画は何ですか?</label>
<ul>
<li>
<input id="m1" type="checkbox" name="movies" value="Space Jam" />
<label for="m1">スペースジャム</label>
</li>
<li>
<input
id="m2"
type="checkbox"
name="movies"
value="Little Rascals"
/>
<label for="m2">リトル・ラスカルズ</label>
</li>
<li>
<input id="m3" type="checkbox" name="movies" value="Frozen" />
<label for="m3">アナと雪の女王</label>
</li>
<li>
<input id="m4" type="checkbox" name="movies" value="Home Alone" />
<label for="m4">ホームアローン</label>
</li>
</ul>
</div>
<button type="submit">送信</button>
</form>
</body>
</html>

このHTMLドキュメントには、ユーザーが記入するためのいくつかのフィールドを含むフォームが含まれています。フォーム内に検証ルールがないため、すべてのフィールドはオプションであり、ユーザーは空のフォームを送信できます。この例では、これは意図された動作です。

Worker

HTMLフォームは完成し、デプロイの準備が整いました。このフォームが送信されると、すべてのデータがPOSTリクエストとして/api/submit URLに送信されます。これはフォームのmethodaction属性によるものです。しかし、現在/api/submitアドレスにはリクエストハンドラーがありません。これを作成します。

Cloudflare Pagesは、動的な動作のためにWorkerを定義してデプロイすることを可能にするFunctions機能を提供しています。

Functionsはfunctionsディレクトリにリンクされており、functionsファイル構造に関連してURLリクエストハンドラーを便利に構築します。たとえば、functions/about.jsファイルは/about URLにマッピングされ、functions/hello/[name].js/hello/:name URLパターンを処理します。ここで、:nameは一致するURLセグメントです。詳細については、Functions routingドキュメントを参照してください。

/api/submitのハンドラーを定義するには、functions/api/submit.jsファイルを作成する必要があります。これにより、functionspublicディレクトリが兄弟関係になり、プロジェクト構造は次のようになります:

├── functions
│   └── api
│   └── submit.js
└── public
└── index.html

<form>POSTリクエストを送信するため、functions/api/submit.jsファイルはonRequestPostハンドラーをエクスポートする必要があります:

/**
* POST /api/submit
*/
export async function onRequestPost(context) {
// TODO: フォーム送信を処理する
}

contextパラメータは、いくつかの潜在的に興味深い値で満たされたオブジェクトです。この例では、Requestオブジェクトのみが必要で、context.requestキーを介してアクセスできます。

前述のように、<form>は送信時にデフォルトでapplication/x-www-form-urlencoded MIMEタイプを使用します。そして、より高度なシナリオでは、enctype="multipart/form-data"属性が必要です。幸いなことに、両方のMIMEタイプはFormDataとして解析および処理できます。これは、Workers — つまりPages Functionsを含む — を使用することで、ネイティブのRequest.formDataパーサーを使用できることを意味します。

説明のために、例アプリケーションのフォームハンドラーは、受信したすべての値で応答します。ハンドラーは常にResponseを返す必要があります。

/**
* POST /api/submit
*/
export async function onRequestPost(context) {
try {
let input = await context.request.formData();
let pretty = JSON.stringify([...input], null, 2);
return new Response(pretty, {
headers: {
"Content-Type": "application/json;charset=utf-8",
},
});
} catch (err) {
return new Response("JSONコンテンツの解析中にエラーが発生しました", { status: 400 });
}
}

このハンドラーが設置されると、例は完全に機能するようになります。送信が受信されると、WorkerはFormDataのキーと値のペアのJSONリストで応答します。

ただし、キーと値のペア(配列の配列)ではなく、JSONオブジェクトで応答したい場合は、手動で行う必要があります。最近、JavaScriptはObject.fromEntriesユーティリティを追加しました。これはいくつかのケースでうまく機能しますが、例の<form>には複数の値を許可するmoviesチェックリストが含まれています。Object.fromEntriesを使用すると、生成されたオブジェクトはmoviesの値のうち1つだけを保持し、残りは破棄されます。これを避けるために、自分自身のFormDataからObjectへのユーティリティを書く必要があります:

/**
* POST /api/submit
*/
export async function onRequestPost(context) {
try {
let input = await context.request.formData();
// FormDataをJSONに変換
// 注意: キーごとに複数の値を許可
let output = {};
for (let [key, value] of input) {
let tmp = output[key];
if (tmp === undefined) {
output[key] = value;
} else {
output[key] = [].concat(tmp, value);
}
}
let pretty = JSON.stringify(output, null, 2);
return new Response(pretty, {
headers: {
"Content-Type": "application/json;charset=utf-8",
},
});
} catch (err) {
return new Response("JSONコンテンツの解析中にエラーが発生しました", { status: 400 });
}
}

最終的なスニペット(上記)は、Workerがすべての値を保持し、<form>送信の正確な表現を持つJSON応答を返すことを可能にします。

デプロイメント

これでプロジェクトをデプロイする準備が整いました。

まだ行っていない場合は、git内で進捗を保存し、コミットをGitHubリポジトリにプッシュしてください:

Terminal window
# すべてのファイルを追加
git add -A
# メッセージ付きでコミット
git commit -m "動作例"
# リモートにコミットをプッシュ
git push -u origin main

あなたの作業は現在GitHubリポジトリ内にあり、Pagesもそれにアクセスできるようになります。

これが初めてのCloudflare Pagesプロジェクトである場合は、スタートガイドを参照して完全な手順を確認してください。適切なGitHubリポジトリを選択した後、次のビルド設定でプロジェクトを構成する必要があります:

  • プロジェクト名 – お好きな名前
  • プロダクションブランチmain
  • フレームワークプリセット – なし
  • ビルドコマンド – なし / 空
  • ビルド出力ディレクトリpublic

保存してデプロイボタンをクリックすると、あなたのPagesプロジェクトは最初のデプロイを開始します。成功すると、ユニークな*.pages.devサブドメインとライブデモへのリンクが表示されます。

このチュートリアルでは、Cloudflare PagesとそのWorkers統合を使用して、ウェブサイトとそのバックエンドロジックを構築し、デプロイしました。Workerハンドラーと通信するフォームを持つ静的HTMLドキュメントを作成し、送信リクエストを解析しました。

このアプリケーションの完全なソースコードを確認したい場合は、GitHubで見つけることができます。

関連リソース