← Cloudflare Pages / pages / tutorials
Создайте HTML-форму
В этом руководстве вы создадите простой <form> с помощью обычных HTML и CSS и развернуть ее на Cloudflare Pages. По ходу дела вы узнаете о некоторых атрибутах HTML-форм и о том, как собирать отправленные данные внутри Worker.
В этом руководстве активно используются Cloudflare Pages и его интеграция с Workers. См. Руководство по началу работы руководство, чтобы ознакомиться с платформой.
Обзор
В вебе формы служат распространённым способом взаимодействия пользователя с веб-документом. Они позволяют пользователю вводить данные и, как правило, отправлять их на сервер. Форма состоит как минимум из одного поля ввода, которое может быть текстовым, выпадающим списком, флажком и так далее.
Каждый вход должен быть назван с использованием name ↗ атрибут, чтобы значение поля имело понятный идентификатор при получении сервером. Кроме того, с появлением HTML5 элементы формы могут объявлять дополнительные атрибуты для включения автоматической валидации формы. Доступные проверки зависят от типа поля, например текстовое поле, принимающее email-адреса (через 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">Submit</button>
</form>Если для формы HTML5 заданы правила валидации, браузеры автоматически проверяют все правила при попытке пользователя отправить форму. При наличии ошибок отправка блокируется, и браузер показывает пользователю сообщения об ошибках для исправления. Атрибут <form> будет только POST данные в /submit конечную точку, если ошибок проверки не осталось. Весь этот процесс встроен в HTML5 и требует только правильных атрибутов формы и полей ввода: JavaScript не нужен.
У элементов формы также может быть <label> ↗ элемент, связанный с ним: это позволяет чётко описать каждое поле ввода. Разумеется, здесь важна визуальная ясность, но структурированная HTML-разметка также делает интерфейс доступнее. Ассистивные технологии выигрывают от этого напрямую. Например, программы чтения с экрана могут объявить, какой <input> получает фокус. А когда <label> нажат, фокус вместо этого переходит на связанное с ним поле формы, что увеличивает область активации поля.
Чтобы включить эту функцию, создайте <label> элемент для каждого поля ввода и назначить каждому <input> элемент и уникальный id значение атрибута. <label> также должен иметь for ↗ атрибут, отражающий уникальный id значение. Изменение предыдущего фрагмента кода должно дать следующий результат:
<form method="POST" action="/api/submit">
<label for="i-fullname">Full Name</label>
<input
id="i-fullname"
type="text"
name="fullname"
pattern="[A-Za-z]+"
required
/>
<label for="i-email">Email Address</label>
<input id="i-email" type="email" name="email" required />
<label for="i-age">Your Age</label>
<input id="i-age" type="number" name="age" min="18" required />
<button type="submit">Submit</button>
</form>Когда этот <form> отправлена с корректными данными, её содержимое передаётся на сервер. Вы можете настроить, как и куда отправляются эти данные, указав соответствующие атрибуты самой формы. Если вы не укажете эти параметры, <form> отправит запрос GET на текущий адрес URL, что редко является желаемым поведением. Чтобы исправить это, необходимо как минимум определить action ↗ атрибут с целевым URL-адресом, но указание method ↗ также обычно рекомендуется указывать, даже если вы переопределяете значение по умолчанию для GET значение.
По умолчанию HTML-формы отправляют своё содержимое в формате application/x-www-form-urlencoded MIME-тип. Это значение будет отражено в Content-Type HTTP-заголовок, который принимающий сервер должен прочитать, чтобы определить, как разбирать содержимое данных. Вы можете настроить MIME-тип через enctype ↗ атрибут. Например, чтобы принимать файлы (через type=file), вам нужно изменить enctype к multipart/form-data значение:
<form method="POST" action="/api/submit" enctype="multipart/form-data">
<label for="i-fullname">Full Name</label>
<input
id="i-fullname"
type="text"
name="fullname"
pattern="[A-Za-z]+"
required
/>
<label for="i-email">Email Address</label>
<input id="i-email" type="email" name="email" required />
<label for="i-age">Your Age</label>
<input id="i-age" type="number" name="age" min="18" required />
<label for="i-avatar">Profile Picture</label>
<input id="i-avatar" type="file" name="avatar" required />
<button type="submit">Submit</button>
</form>Поскольку enctype изменяется, браузер также меняет способ отправки данных на сервер. Content-Type HTTP-заголовок будет отражать новый подход, а тело HTTP-запроса будет соответствовать новому MIME-типу. Принимающий сервер должен поддерживать новый формат и соответствующим образом изменить способ разбора запроса.
Пример в действии
Оставшаяся часть этого руководства посвящена созданию HTML-формы на Pages, включая Worker для получения и разбора отправленных данных формы.
Настройка
Для начала создайте новый репозиторий GitHub ↗. Затем создайте новый локальный каталог на своем компьютере, инициализируйте git и подключите расположение GitHub в качестве удаленного репозитория:
# create new directory
mkdir new-project
# enter new directory
cd new-project
# initialize git
git init
# attach remote
git remote add origin [email protected]:<username>/<repo>.git
# change default branch name
git branch -M mainТеперь можно приступить к работе в new-project директорию, которую вы создали.
Разметка
Форма для этого примера довольно проста. Она включает набор различных типов полей ввода, в том числе флажки для выбора нескольких значений. Форма также не содержит проверок, чтобы можно было увидеть, как сервер интерпретирует пустые или отсутствующие значения.
В этом примере проекта используется только обычный HTML. Можно использовать любой предпочитаемый JavaScript-фреймворк, но для простоты и наглядности выбраны базовые языки: все фреймворки в той или иной степени абстрагируют или дают похожий результат.
Создайте public/index.html в каталоге вашего проекта. Все ресурсы фронтенда будут находиться в этой public директория и этот index.html файл будет служить главной страницей сайта.
Скопируйте и вставьте следующее содержимое в public/index.html файле:
<html lang="en">
<head>
<meta charset="utf8" />
<title>Form Demo</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">Full Name</label>
<input id="name" name="name" type="text" />
</div>
<div class="input">
<label for="email">Email Address</label>
<input id="email" name="email" type="email" />
</div>
<div class="input">
<label for="referers">How did you hear about us?</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">Friends</option>
</select>
</div>
<div class="checklist">
<label>What are your favorite movies?</label>
<ul>
<li>
<input id="m1" type="checkbox" name="movies" value="Space Jam" />
<label for="m1">Space Jam</label>
</li>
<li>
<input
id="m2"
type="checkbox"
name="movies"
value="Little Rascals"
/>
<label for="m2">Little Rascals</label>
</li>
<li>
<input id="m3" type="checkbox" name="movies" value="Frozen" />
<label for="m3">Frozen</label>
</li>
<li>
<input id="m4" type="checkbox" name="movies" value="Home Alone" />
<label for="m4">Home Alone</label>
</li>
</ul>
</div>
<button type="submit">Submit</button>
</form>
</body>
</html>Этот HTML документ будет содержать форму с несколькими полями для заполнения пользователем. Поскольку в форме нет правил валидации, все поля необязательны, и пользователь может отправить пустую форму. В этом примере такое поведение предусмотрено намеренно.
Worker
HTML-форма готова к развёртыванию. При отправке этой формы все данные будут отправлены в виде POST запрос к /api/submit URL. Это связано с тем, что method и action атрибуты. Однако в настоящее время обработчик запросов по адресу /api/submit адрес. Сейчас вы его создадите.
Cloudflare Pages предлагает Функции функцию, которая позволяет определять и развёртывать Workers для динамического поведения.
Functions связаны с functions директория, что удобно для формирования обработчиков URL запросов относительно functions структуру файлов. Например, functions/about.js файл будет сопоставлен с /about URL и functions/hello/[name].js будет обрабатывать /hello/:name шаблон URL, где :name обозначает любой совпадающий сегмент URL. См. Маршрутизация Functions документации.
Чтобы определить обработчик для /api/submit, необходимо создать functions/api/submit.js файл. Это означает, что ваш functions и public директории должны находиться на одном уровне, а общая структура проекта должна выглядеть примерно так:
├── functions
│ └── api
│ └── submit.js
└── public
└── index.html <form> отправит POST запросы, а значит, functions/api/submit.js файл должен экспортировать onRequestPost обработчик:
/**
* POST /api/submit
*/
export async function onRequestPost(context) {
// TODO: Handle the form submission
} 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("Error parsing JSON content", { status: 400 });
}
}После добавления этого обработчика пример становится полностью работоспособным. При получении отправки Worker ответит JSON-списком FormData пар «ключ-значение».
Однако если вы хотите отвечать объектом JSON вместо пар ключ-значение (массива массивов), это нужно делать вручную. Недавно в JavaScript появился Object.fromEntries ↗ утилита. В некоторых случаях это хорошо работает, однако пример <form> включает movies список флажков, допускающий несколько значений. При использовании Object.fromEntries, сгенерированный объект сохранит только один из movies значения, отбрасывая остальные. Чтобы избежать этого, необходимо написать собственный FormData к Object утилиту:
/**
* POST /api/submit
*/
export async function onRequestPost(context) {
try {
let input = await context.request.formData();
// Convert FormData to JSON
// NOTE: Allows multiple values per key
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("Error parsing JSON content", { status: 400 });
}
}Приведённый выше фрагмент кода позволяет Worker сохранить все значения и вернуть JSON-ответ, точно отражающий <form> отправка.
Развёртывание
Теперь можно развернуть проект.
Если вы еще этого не сделали, сохраните прогресс в git и затем отправьте коммит (или несколько коммитов) в репозиторий GitHub:
# Add all files
git add -A
# Commit w/ message
git commit -m "working example"
# Push commit(s) to remote
git push -u origin mainТеперь ваш код находится в репозитории GitHub, а значит, Pages тоже имеет к нему доступ.
Если это ваш первый проект Cloudflare Pages, ознакомьтесь с Руководство по началу работы для полного пошагового руководства. После выбора нужного репозитория GitHub необходимо настроить проект со следующими параметрами сборки:
- Название проекта : На ваш выбор
- Продакшен-ветка,
main - Framework preset : Нет
- Команда сборки : Нет / Пусто
- Каталог вывода сборки,
public
После нажатия на Save and Deploy кнопку, ваш проект Pages начнёт первый деплой. В случае успеха вам будет предоставлен уникальный *.pages.dev поддомен и ссылку на демонстрацию вашего проекта.
В этом руководстве вы создали и развернули сайт вместе с серверной логикой с помощью Cloudflare Pages и его интеграции с Workers. Вы создали статический HTML-документ с формой, которая взаимодействует с обработчиком Worker для разбора запросов на отправку.
Если вы хотите просмотреть полный исходный код этого приложения, вы можете найти его на GitHub ↗.