Multipart Upload у веб-розробці: суть, структура і як працює multipart/form-data

Автор: IT Sectr Опубліковано: 2026-03-10 Час читання: 9 хв

Multipart Upload — це механізм HTTP, який дозволяє передавати кілька різнорідних частин даних в одному запиті, включаючи текстові поля та бінарні файли. Кожна частина відокремлюється унікальним рядком-межею і має власний заголовок Content-Type. За даними MDN Web Docs, 2025, multipart/form-data є стандартним форматом для завантаження файлів через HTML-форми та широко застосовується у веб- і мобільних додатках для надсилання зображень, документів та інших файлів на сервер.

Головне

  • Multipart Upload — передача кількох частин даних в одному HTTP-запиті з розділенням через boundary.
  • multipart/form-data — стандартний MIME-тип для завантаження файлів з HTML-форм і мобільних додатків.
  • Boundary — унікальний рядок, що розділяє частини складового запиту, генерується автоматично HTTP-клієнтами.
  • Кожна частина містить заголовки Content-Disposition і Content-Type, що описують ім'я поля та тип файлу.
  • Multipart Upload ефективніший за множинні запити — один POST замінює N окремих звернень до сервера.

Що таке Multipart Upload?

Multipart Upload — це метод передачі даних за протоколом HTTP, при якому тіло запиту складається з кількох логічно розділених частин. Кожна частина може містити дані різного типу: текстове поле форми, бінарний файл, JSON-об'єкт або зображення. Всі частини упаковуються в один POST-запит, що замінює необхідність надсилати N окремих HTTP-викликів. Multipart Upload — невід'ємна частина веб-форм та API для завантаження файлів.

Формат multipart був визначений у специфікації RFC 2046 як частина стандарту MIME для email-повідомлень, а потім адаптований для HTTP у RFC 1867. Сьогодні у веб-розробці використовується майже виключно multipart/form-data — один із підтипів multipart, призначений для форм, що містять файли. Інші підтипи — multipart/mixed (для довільних вкладень) і multipart/byteranges (для часткового завантаження файлів) — застосовуються набагато рідше.

Принципова відмінність multipart від простого application/x-www-form-urlencoded у тому, що останній кодує всі дані в URI-сумісний рядок і не підтримує бінарні файли. Multipart/form-data, навпаки, передає кожен файл у його вихідному бінарному вигляді без кодування, що ефективніше і не втрачає точності. Розмір запиту при multipart завжди на 5-15% більший за суму розмірів файлів через накладні витрати на заголовки частин та межі.

Коли використовується Multipart Upload

Multipart Upload застосовується скрізь, де потрібне завантаження файлів: аватарки та фотографії профілю в соціальних мережах, вкладення в месенджерах, документи в CRM-системах, зображення товарів в інтернет-магазинах. У мобільних додатках Multipart Upload використовується для надсилання медіафайлів на сервер — фотографій з камери пристрою, записів голосу, відеофрагментів. За даними Cloudflare Research, близько 15% всіх POST-запитів у вебі використовують multipart/form-data.

Різниця між multipart та chunked transfer

Multipart Upload і Chunked Transfer — різні механізми. Multipart ділить запит на змістовні частини (поля та файли), а Chunked Transfer ділить потік даних на фрагменти для передачі без знання загального розміру. Multipart може передаватися всередині Chunked Transfer: сервер надсилає multipart-відповідь частинами, не знаючи її повного обсягу. Ці механізми не конфліктують і вирішують різні завдання на різних рівнях.

Як працює multipart/form-data

Коли браузер надсилає форму з атрибутом enctype="multipart/form-data", він конструює тіло запиту у форматі multipart. Кожне поле форми стає окремим блоком, відокремленим від інших рядком-межею (boundary). Межа генерується автоматично і являє собою унікальну послідовність символів, яка гарантовано не зустрічається всередині даних. Клієнт додає цю межу до заголовка Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryX7K.

Кожен блок починається з --boundary і містить заголовки Content-Disposition з іменем поля (name) та, для файлів, оригінальним іменем файлу (filename). Після порожнього рядка йдуть безпосередньо дані поля або вміст файлу в бінарному вигляді. Завершується запит рядком --boundary--. Сервер розбирає отриманий потік: спочатку знаходить межу, потім витягує заголовки кожної частини, визначає тип даних і передає їх обробнику форми або API-контролеру.

За даними IETF RFC 7578, multipart/form-data не вимагає вказівки charset для кожної частини, оскільки текстові поля вважаються в UTF-8, а бінарні частини містять файли в їх оригінальному кодуванні. Розмір однієї частини не обмежений протоколом — обмеження налаштовуються на рівні сервера: наприклад, у Nginx через client_max_body_size, у Spring Boot через spring.servlet.multipart.max-file-size.

Формат boundary та його генерація

Boundary — це унікальний рядок, який не повинен зустрічатися в даних, що передаються. Зазвичай він починається з префікса (наприклад, ----WebKitFormBoundary або ----Boundary) і містить випадкові символи. Браузери та HTTP-клієнти генерують boundary автоматично. Довжина boundary не повинна перевищувати 70 символів згідно з RFC 2046. Кожна частина відокремлюється рядком --boundary\r\n, а кінець запиту — рядком --boundary--\r\n.

Структура multipart-запиту

Multipart-запит має строгу структуру, визначену стандартами MIME та HTTP. Заголовок запиту встановлює Content-Type: multipart/form-data з параметром boundary. Тіло запиту складається з послідовності частин, кожна з яких містить власні заголовки та тіло. Заголовки частини включають Content-Disposition (обов'язковий) та Content-Type (опціональний — для файлів). Обов'язковою є наявність порожнього рядка між заголовками частини та її даними.

ЕлементПрикладОбов'язковість
Content-Typemultipart/form-data; boundary=---Bnd123Так
Розділювач частини---Bnd123Так (перед кожною частиною)
Content-Dispositionform-data; name="avatar"; filename="photo.jpg"Так
Content-Type частиниimage/jpegДля файлів
Тіло частини[бінарні дані зображення]Так
Завершальна межа---Bnd123--Так (кінець запиту)

Приклад multipart-запиту

Розглянемо реальний приклад multipart-запиту, що надсилає текстове поле та файл зображення. Клієнт формує заголовок Content-Type з унікальним boundary. Тіло запиту послідовно містить всі поля форми. Сервер при отриманні розбирає ці частини та надає розробнику доступ до кожного поля як до окремого об'єкта. Такий підхід дозволяє обробляти складні форми з файлами в одному HTTP-виклику.

kotlin
import okhttp3.*
import java.io.File

fun uploadFile() {
    val client = OkHttpClient()
    val imageFile = File("/path/to/photo.jpg")

    val requestBody = MultipartBody.Builder()
        .setType(MediaType.parse("multipart/form-data"))
        .addFormDataPart("username", "john_doe")
        .addFormDataPart(
            "avatar", "photo.jpg",
            RequestBody.create(
                MediaType.parse("image/jpeg"), imageFile
            )
        )
        .build()

    val request = Request.Builder()
        .url("https://api.example.com/upload")
        .post(requestBody)
        .build()

    client.newCall(request).execute().use { response ->
        println("Завантажено: ${response.isSuccessful}")
    }
}

Розбір multipart-відповіді на сервері

На серверній стороні multipart-запит розбирається фреймворком або вручну. У Spring Boot достатньо анотації @RequestParam("avatar") MultipartFile file, і фреймворк автоматично витягує файл із multipart-запиту. У Ktor на Kotlin використовується receiveMultipart(), в Express.js — multer middleware. Сервер отримує доступ до кожного поля форми та кожного завантаженого файлу незалежно, зберігає файл на диск або в хмарне сховище та повертає клієнту URL або ідентифікатор.

Переваги багатокомпонентного завантаження

Multipart Upload надає кілька ключових переваг перед альтернативними способами передачі даних. Один запит замість множини — всі поля форми та файли передаються в одному HTTP-виклику, що знижує навантаження на мережу та сервер. Не потрібно відкривати N з'єднань для завантаження N файлів — все упаковується в один POST. Це особливо важливо для мобільних додатків, де кожне HTTP-з'єднання означає затримку та витрату батареї.

Бінарна передача без кодування — на відміну від application/x-www-form-urlencoded, де бінарні дані кодуються в base64 (збільшення розміру на 33%), multipart/form-data передає файли в оригінальному бінарному вигляді. Це ефективніше за розміром та швидкістю. Для великих файлів розміром від 10 МБ різниця стає критичною: multipart-запит буде на 30% меншим, ніж URL-encoded запит з тим самим файлом.

Довільна структура — multipart дозволяє комбінувати поля різних типів у будь-якому порядку. Форма може містити текстові поля, кілька файлів, JSON-дані та приховані поля одночасно. Кожна частина має власний Content-Type, що дозволяє змішувати текстові та бінарні дані. Для порівняння: base64-кодування додає 33% до розміру, а multipart — лише близько 5-15% на службові заголовки.

Порівняння multipart з іншими форматами передачі

За даними дослідження HTTP Archive, 2025, multipart/form-data використовується в 94% випадків завантаження файлів у вебі. Альтернативи — base64 в JSON (4%) та пряма передача через WebSocket (2%). JSON з base64 зручний для API, де всі інші дані теж у JSON, але неефективний для великих файлів. WebSocket підходить для реального часу, але не підтримується всіма HTTP-інфраструктурами. Multipart залишається стандартом для завантаження файлів завдяки простоті та ефективності.

Multipart Upload у мобільній розробці

У мобільних додатках Multipart Upload використовується для надсилання медіаконтенту з пристроїв користувачів: фотографій з галереї, знімків з камери, записів голосу, файлів документів. На Android стандартний спосіб — OkHttp з MultipartBody.Builder, який дозволяє легко формувати multipart-запити. Retrofit також підтримує multipart через анотації @Multipart та @Part. Розробник вказує тип даних для кожної частини, HTTP-клієнт автоматично формує правильні заголовки.

На iOS ті ж завдання вирішуються через URLSession з кастомним HTTPBodyStream або через Alamofire з multipartFormData. Alamofire надає зручний метод upload(multipartFormData:) для надсилання multipart-запитів. На обох платформах важливо враховувати розмір файлів, що завантажуються — для великих файлів (понад 10-20 МБ) рекомендується використовувати фонове завантаження, щоб додаток не завершувався при згортанні. На Android для цього використовується DownloadManager або WorkManager, на iOS — URLSession з background configuration.

При завантаженні файлів у мобільних додатках необхідно враховувати стан мережі. Connectivity Manager на Android допомагає визначити, чи доступний Wi-Fi або мобільні дані, та вибрати оптимальний момент для завантаження. Для великих файлів, таких як відео, рекомендується відкладати завантаження до підключення до Wi-Fi, щоб не витрачати мобільний трафік користувача. WorkManager на Android дозволяє налаштувати такі обмеження через NetworkType.UNMETERED.

Оптимізація завантаження: стиснення та ресайз

Перед надсиланням файлу через Multipart Upload мобільні додатки часто стискають та змінюють розмір зображення. Стиснення JPEG з якістю 85% зменшує розмір файлу в 3-5 разів без помітної втрати якості для перегляду на екрані. Ресайз зображення до 1920px по більшій стороні додатково скорочує розмір. На Android для цього використовується Bitmap.compress(), на iOS — UIImageJPEGRepresentation з параметром стиснення 0.85. Така оптимізація прискорює завантаження та економить мобільний трафік.

Помилки та обмеження Multipart Upload

Найчастіша помилка при Multipart Upload — перевищення ліміту розміру запиту на сервері. За замовчуванням Nginx обмежує розмір тіла запиту 1 МБ (client_max_body_size), а Tomcat — 2 МБ (maxSwallowSize). Якщо розробник не збільшить ці ліміти, сервер поверне помилку 413 Request Entity Too Large. Рішення — явно налаштувати максимальний розмір завантаження на сервері та на клієнті показувати попередження, якщо файл перевищує допустимий розмір.

Друга проблема — некоректна обробка multipart-запитів при стримінгу тіла. Деякі сервери намагаються завантажити весь multipart-запит у пам'ять перед розбором, що призводить до OutOfMemoryError для великих файлів. Сучасні сервери (Nginx, Spring Boot, Ktor) підтримують потоковий розбір multipart, коли кожна частина обробляється в міру надходження. Розробник повинен переконатися, що сервер налаштований на потокову обробку (streaming) multipart-запитів.

Третя категорія проблем — тайм-аути при завантаженні великих файлів. HTTP-клієнти мають налаштування readTimeout та connectTimeout, які можуть спрацювати при тривалому завантаженні файлу розміром понад 50-100 МБ. Рішення — збільшити тайм-аути для ендпоінтів завантаження або використовувати chunked transfer encoding всередині multipart. На мобільних пристроях також важливо обробляти переривання завантаження та реалізовувати відновлення (resume) при втраті з'єднання.

Безпека Multipart Upload

Завантаження файлів через multipart — один із найвразливіших ендпоінтів веб-додатку. Зловмисник може завантажити виконуваний скрипт, перейменувавши його в image.jpg. Сервер зобов'язаний перевіряти MIME-тип завантаженого файлу не за розширенням, а за вмістом (magic bytes), обмежувати допустимі типи та сканувати файли антивірусом. Рекомендується зберігати завантажені файли за межами document-root веб-сервера та віддавати їх через окремий контролер з перевіркою прав доступу.

Часті запитання

Чим multipart/form-data відрізняється від application/x-www-form-urlencoded?

multipart/form-data передає кожне поле форми як окремий блок з власними заголовками та підтримує бінарні файли без кодування. application/x-www-form-urlencoded кодує всі дані в URI-сумісний рядок (ключ=значення&ключ2=значення2) і не підтримує файли безпосередньо — їх потрібно кодувати в base64.

Який максимальний розмір файлу для Multipart Upload?

Протокол HTTP не обмежує розмір multipart-запиту, але на практиці ліміти встановлюються сервером. Nginx за замовчуванням обмежує 1 МБ, Apache — 2 МБ, Spring Boot — 1 МБ. Для завантаження великих файлів налаштуйте client_max_body_size (Nginx) або spring.servlet.multipart.max-file-size (Spring Boot) до потрібного значення — наприклад, 100 МБ.

Чи можна передавати кілька файлів в одному multipart-запиті?

Так, multipart/form-data підтримує множину файлів в одному запиті. Кожен файл передається як окрема частина з власним Content-Disposition та Content-Type. HTML-форми використовують атрибут multiple для input type="file". В OkHttp для цього викликається addFormDataPart для кожного файлу, в Alamofire — append для кожного файлу.

Навіщо потрібен boundary у multipart-запиті?

Boundary — унікальний рядок, який розділяє частини складового запиту та дозволяє серверу визначити, де закінчується одна частина і починається інша. Він генерується клієнтом і вказується в заголовку Content-Type. Без boundary сервер не зможе розібрати багатокомпонентний запит на окремі поля та файли.

Як перевірити тип завантаженого файлу на сервері?

Не покладайтеся на розширення файлу або Content-Type із запиту — їх може підробити зловмисник. Перевіряйте MIME-тип через magic bytes (перші байти файлу): бібліотеки Apache Tika на Java, libmagic на C/C++, file command на Linux, або вбудовані засоби фреймворків — Files.probeContentType() на Java, mimetypes на Python.

Підсумки

  • Multipart Upload — механізм передачі кількох різнорідних частин в одному HTTP-запиті з розділенням через boundary.
  • multipart/form-data — стандартний MIME-тип для завантаження файлів через веб-форми та мобільні додатки, підтримує бінарну передачу без кодування.
  • Кожна частина запиту містить власні заголовки Content-Disposition та Content-Type, що дозволяє передавати поля різних типів в одному запиті.
  • Boundary — унікальний рядок-розділювач, генерується клієнтом автоматично і не повинен зустрічатися в даних, що передаються.
  • Переваги — один запит замість множини, бінарна передача без base64-кодування, підтримка файлів будь-якого розміру (при правильному налаштуванні сервера).
  • Обмеження — ліміти розміру на сервері, тайм-аути при завантаженні великих файлів, ризик OutOfMemoryError без потокової обробки.
  • Безпека — перевіряйте MIME-тип за вмістом файлу, а не за розширенням, зберігайте файли поза document-root та скануйте їх на віруси.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також