Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як відправити форму з файлами через fetch і FormData?

FormData збирає дані форми у формат, який браузер відправляє так само, як звичайна HTML-форма, - зокрема з файлами.

const form = document.querySelector('#profile-form');

form.addEventListener('submit', async (event) => {
  event.preventDefault();

  const data = new FormData(form);          // усі поля з атрибутом name, включно з файлами
  data.append('source', 'web');             // додаткове поле

  const response = await fetch(form.action, {
    method: 'POST',
    body: data,
    headers: { Accept: 'application/json' },
  });
});

Найчастіша помилка - вручну задати Content-Type:

headers: { 'Content-Type': 'multipart/form-data' }   // зламає запит

Для multipart/form-data заголовок обов'язково містить межу (boundary), що розділяє частини: multipart/form-data; boundary=----WebKitFormBoundary.... Браузер генерує її сам, якщо тіло - FormData. Вказаний вручну заголовок межі не має - сервер не зможе розібрати запит.

Корисні методи:

data.get('email');                    // значення поля
data.getAll('tags[]');                // усі значення поля з однаковою назвою
data.set('email', 'new@example.com'); // замінити
data.delete('password_confirmation');
Object.fromEntries(data);             // в об'єкт (для полів без повторів)

Файли: <input type="file" name="avatar"> потрапляє у FormData автоматично. Додати файл чи Blob вручну - data.append('avatar', file, 'avatar.png').

Особливості з Laravel:

  • PUT/PATCH з файлами: PHP історично розбирає multipart/form-data лише для POST. Для оновлення з файлами відправляють POST з підміною методу: data.append('_method', 'PUT');
  • CSRF: для форм, що відправляються fetch-ем, токен з поля _token потрапить у FormData сам, якщо в Blade-формі є @csrf;
  • Accept: application/json - щоб Laravel при помилці валідації повернув JSON 422 з полем errors, а не редирект назад;
  • масиви називають як у HTML: tags[], items[0][qty] - Laravel розбере їх у вкладені масиви.

Коли не FormData: якщо файлів немає, а API приймає JSON, простіше body: JSON.stringify(payload) з Content-Type: application/json.

Прогрес завантаження великого файлу fetch наразі не показує. Для смуги прогресу використовують XMLHttpRequest (подія upload.onprogress) або бібліотеку на кшталт axios, що використовує його всередині.

Докладніше в документації: FormData

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання