FormData: что попадает в отправляемую форму

2 мин чтения

Какие поля попадают в FormData и почему Content-Type с multipart boundary лучше оставить браузеру.

Какие поля отправляет форма
  1. Элементы формыУчитываем name и состояние disabled
  2. FormDataСобирает участвующие в отправке поля
  3. FetchБраузер задаёт multipart boundary сам

На экране форма заполнена, а на сервере части значений нет. Для FormData важно не то, что видно пользователю, а имя поля, его состояние и правила отправки формы. Посмотрим на небольшой пример с файлом: какие данные войдут в запрос и какой заголовок браузер должен добавить сам.

Форма с текстом и файлом

<form id="feedback">
  <input name="subject" value="Документация">
  <textarea name="message">Уточните пример</textarea>
  <input name="internal" value="Черновик" disabled>
  <input type="file" name="attachment">
  <button>Отправить</button>
</form>
<script>
document.querySelector('#feedback').addEventListener('submit', function (event) {
  event.preventDefault();
  const data = new FormData(event.currentTarget);
  data.append('source', 'help-page');
  const request = new XMLHttpRequest();
  request.open('POST', '/feedback');
  request.onload = function () {
    console.log(request.status);
  };
  request.onerror = function () {
    console.log('Сетевая ошибка');
  };
  request.send(data);
});
</script>

В FormData передаётся сама форма. Отключённое поле internal не попадёт в набор. Элемент без name тоже не создаёт обычную именованную запись. Имена должны совпадать с ожидаемым сервером контрактом, а не с видимыми подписями. Дополнительный source добавляется программно и должен проходить серверную проверку наравне с другими значениями: пользователь может отправить собственный запрос.

Заголовок формирует браузер

При передаче FormData не задавайте вручную Content-Type multipart/form-data. Браузер добавляет к нему boundary, согласованный с фактическим телом. Заголовок без подходящей границы мешает серверу разобрать поля. Не преобразуйте такой набор автоматически в URLSearchParams, если в нём есть файлы: текстовая сериализация не сохраняет их содержимое. Выбор формата зависит от контракта маршрута, а не только от удобства одной строки кода.

FormData не выполняет проверку доступа и не гарантирует, что сервер принял файл. Обработчик onload срабатывает и для HTTP-ответа с ошибкой, поэтому нужно проверять status и согласованный формат ответа. Сетевая ошибка обрабатывается отдельно. Поддержку нужных методов и вариантов конструктора проверьте в браузерах, с которыми работает приложение.

Как проверить состав запроса

В панели сети сравните отправку с файлом и без него. Поля subject, message и source должны присутствовать, internal — отсутствовать. Проверьте большой файл и потерю сети, а на сервере — имена полей, ограничения размера и статус обработки. Содержимое чужих вложений для диагностики в общий журнал не записывайте.

Источники и дальнейшее чтение