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 стандарда за имејл поруке, а затим прилагођен за 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 захтев се анализира од стране framework-а или ручно. У Spring Boot-у довољна је анотација @RequestParam("avatar") MultipartFile file, и framework аутоматски издваја датотеку из 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 MB навише, разлика постаје критична: 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 MB) препоручује се коришћење отпремања у позадини како се апликација не би затворила при минимизацији. На Android-у се за то користи DownloadManager или WorkManager, на iOS-у — URLSession са background конфигурацијом.

Приликом отпремања датотека у мобилним апликацијама потребно је узети у обзир стање мреже. 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 MB (client_max_body_size), а Tomcat — на 2 MB (maxSwallowSize). Ако програмер не повећа ова ограничења, сервер ће вратити грешку 413 Request Entity Too Large. Решење — експлицитно подесити максималну величину отпремања на серверу и приказати упозорење на клијенту ако датотека прелази дозвољену величину.

Други проблем — некоректна обрада multipart захтева при стримовању тела. Неки сервери покушавају да учитају цео multipart захтев у меморију пре анализе, што доводи до OutOfMemoryError-а за велике датотеке. Модерни сервери (Nginx, Spring Boot, Ktor) подржавају стримовну анализу multipart-а, када се сваки део обрађује како пристиже. Програмер треба да се увери да је сервер подешен за стримовну обраду multipart захтева.

Трећа категорија проблема — тајм-аути при отпремању великих датотека. HTTP клијенти имају подешавања readTimeout и connectTimeout која могу да се активирају при дуготрајном отпремању датотеке веће од 50-100 MB. Решење — повећати тајм-ауте за отпремање ендпоинта или користити 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 MB, Apache — на 2 MB, Spring Boot — на 1 MB. За отпремање великих датотека подесите client_max_body_size (Nginx) или spring.servlet.multipart.max-file-size (Spring Boot) на потребну вредност — на пример, 100 MB.

Може ли се пренети више датотека у једном 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 на Linux, или уграђени алати framework-а — 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. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође