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 для загрузки файлов.

Формат multippart был определён в спецификации 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("Uploaded: ${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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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