Το Multipart Upload είναι ένας μηχανισμός HTTP που επιτρέπει τη μετάδοση πολλών ετερογενών τμημάτων δεδομένων σε ένα μόνο αίτημα, συμπεριλαμβανομένων πεδίων κειμένου και δυαδικών αρχείων. Κάθε τμήμα διαχωρίζεται από μια μοναδική συμβολοσειρά ορίου και έχει τη δική του κεφαλίδα Content-Type. Σύμφωνα με τα MDN Web Docs, 2025, το multipart/form-data είναι η τυπική μορφή για τη μεταφόρτωση αρχείων μέσω φορμών HTML και χρησιμοποιείται ευρέως σε διαδικτυακές και κινητές εφαρμογές για την αποστολή εικόνων, εγγράφων και άλλων αρχείων στον διακομιστή.
Βασικά σημεία
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 χρησιμοποιείται παντού όπου απαιτείται μεταφόρτωση αρχείων: άβαταρ και φωτογραφίες προφίλ στα μέσα κοινωνικής δικτύωσης, συνημμένα σε εφαρμογές μηνυμάτων, έγγραφα σε συστήματα CRM, εικόνες προϊόντων σε ηλεκτρονικά καταστήματα. Σε κινητές εφαρμογές, το Multipart Upload χρησιμοποιείται για την αποστολή πολυμεσικού περιεχομένου στον διακομιστή — φωτογραφίες από την κάμερα της συσκευής, ηχογραφήσεις, αποσπάσματα βίντεο. Σύμφωνα με δεδομένα της Cloudflare Research, περίπου το 15% όλων των αιτημάτων POST στο διαδίκτυο χρησιμοποιούν multipart/form-data.
Multipart Upload και Chunked Transfer είναι διαφορετικοί μηχανισμοί. Το Multipart χωρίζει το αίτημα σε ουσιαστικά μέρη (πεδία και αρχεία), ενώ το Chunked Transfer χωρίζει τη ροή δεδομένων σε θραύσματα για μετάδοση χωρίς γνώση του συνολικού μεγέθους. Το Multipart μπορεί να μεταδοθεί εντός του Chunked Transfer: ο διακομιστής στέλνει την απάντηση multipart σε μέρη, χωρίς να γνωρίζει τον συνολικό όγκο της. Αυτοί οι μηχανισμοί δεν έρχονται σε αντίθεση και επιλύουν διαφορετικές εργασίες σε διαφορετικά επίπεδα.
Όταν το πρόγραμμα περιήγησης στέλνει μια φόρμα με το χαρακτηριστικό 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 είναι μια μοναδική συμβολοσειρά που δεν πρέπει να εμφανίζεται στα μεταδιδόμενα δεδομένα. Συνήθως ξεκινά με ένα πρόθεμα (π.χ. ----WebKitFormBoundary ή ----Boundary) και περιέχει τυχαίους χαρακτήρες. Τα προγράμματα περιήγησης και οι πελάτες HTTP παράγουν το boundary αυτόματα. Το μήκος του boundary δεν πρέπει να υπερβαίνει τους 70 χαρακτήρες σύμφωνα με το RFC 2046. Κάθε τμήμα διαχωρίζεται από τη συμβολοσειρά --boundary\r\n, και το τέλος του αιτήματος από --boundary--\r\n.
Το multipart αίτημα έχει αυστηρή δομή που ορίζεται από τα πρότυπα MIME και HTTP. Η κεφαλίδα του αιτήματος ορίζει Content-Type: multipart/form-data με την παράμετρο boundary. Το σώμα του αιτήματος αποτελείται από μια ακολουθία τμημάτων, καθένα από τα οποία περιέχει τις δικές του κεφαλίδες και σώμα. Οι κεφαλίδες τμήματος περιλαμβάνουν Content-Disposition (υποχρεωτικό) και Content-Type (προαιρετικό — για αρχεία). Η παρουσία κενής γραμμής μεταξύ των κεφαλίδων του τμήματος και των δεδομένων του είναι υποχρεωτική.
| Στοιχείο | Παράδειγμα | Υποχρεωτικό |
|---|---|---|
| Content-Type | multipart/form-data; boundary=---Bnd123 | Ναι |
| Διαχωριστής τμήματος | ---Bnd123 | Ναι (πριν από κάθε τμήμα) |
| Content-Disposition | form-data; name="avatar"; filename="photo.jpg" | Ναι |
| Content-Type τμήματος | image/jpeg | Για αρχεία |
| Σώμα τμήματος | [δυαδικά δεδομένα εικόνας] | Ναι |
| Τελικό όριο | ---Bnd123-- | Ναι (τέλος αιτήματος) |
Ας εξετάσουμε ένα πραγματικό παράδειγμα multipart αιτήματος που στέλνει ένα πεδίο κειμένου και ένα αρχείο εικόνας. Ο πελάτης σχηματίζει την κεφαλίδα Content-Type με ένα μοναδικό boundary. Το σώμα του αιτήματος περιέχει διαδοχικά όλα τα πεδία της φόρμας. Ο διακομιστής κατά τη λήψη αναλύει αυτά τα τμήματα και παρέχει στον προγραμματιστή πρόσβαση σε κάθε πεδίο ως ξεχωριστό αντικείμενο. Αυτή η προσέγγιση επιτρέπει την επεξεργασία σύνθετων φορμών με αρχεία σε μία κλήση HTTP.
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 αίτημα αναλύεται από το πλαίσιο ή χειροκίνητα. Στο Spring Boot, αρκεί ο σχολιασμός @RequestParam("avatar") MultipartFile file, και το πλαίσιο εξάγει αυτόματα το αρχείο από το multipart αίτημα. Στο Ktor σε Kotlin, χρησιμοποιείται το receiveMultipart(), στο Express.js — το middleware multer. Ο διακομιστής αποκτά πρόσβαση σε κάθε πεδίο φόρμας και κάθε μεταφορτωμένο αρχείο ανεξάρτητα, αποθηκεύει το αρχείο σε δίσκο ή αποθήκευση cloud και επιστρέφει στον πελάτη το 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% για κεφαλίδες υπηρεσίας.
Σύμφωνα με τη μελέτη HTTP Archive, 2025, το multipart/form-data χρησιμοποιείται στο 94% των περιπτώσεων μεταφόρτωσης αρχείων στο διαδίκτυο. Εναλλακτικές — base64 σε JSON (4%) και άμεση μετάδοση μέσω WebSocket (2%). Το JSON με base64 είναι βολικό για API όπου όλα τα άλλα δεδομένα είναι επίσης σε JSON, αλλά αναποτελεσματικό για μεγάλα αρχεία. Το WebSocket είναι κατάλληλο για πραγματικό χρόνο, αλλά δεν υποστηρίζεται από όλες τις υποδομές HTTP. Το Multipart παραμένει το πρότυπο για μεταφόρτωση αρχείων χάρη στην απλότητα και αποδοτικότητά του.
Σε κινητές εφαρμογές, το 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 με διαμόρφωση παρασκηνίου.
Κατά τη μεταφόρτωση αρχείων σε κινητές εφαρμογές, πρέπει να λαμβάνεται υπόψη η κατάσταση δικτύου. 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 — υπέρβαση του ορίου μεγέθους αιτήματος στον διακομιστή. Από προεπιλογή, το 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 είναι ένα από τα πιο ευάλωτα τελικά σημεία μιας διαδικτυακής εφαρμογής. Ένας εισβολέας μπορεί να μεταφορτώσει ένα εκτελέσιμο σενάριο μετονομάζοντάς το σε image.jpg. Ο διακομιστής πρέπει να ελέγχει τον τύπο MIME του μεταφορτωμένου αρχείου όχι βάσει επέκτασης, αλλά βάσει περιεχομένου (magic bytes), να περιορίζει τους επιτρεπόμενους τύπους και να σαρώνει τα αρχεία με antivirus. Συνιστάται η αποθήκευση μεταφορτωμένων αρχείων εκτός του document-root του διακομιστή ιστού και η παροχή τους μέσω ξεχωριστού ελεγκτή με έλεγχο δικαιωμάτων πρόσβασης.
Συχνές Ερωτήσεις
multipart/form-data μεταδίδει κάθε πεδίο φόρμας ως ξεχωριστό μπλοκ με δικές του κεφαλίδες και υποστηρίζει δυαδικά αρχεία χωρίς κωδικοποίηση. Το application/x-www-form-urlencoded κωδικοποιεί όλα τα δεδομένα σε μια συμβολοσειρά συμβατή με URI (κλειδί=τιμή&κλειδί2=τιμή2) και δεν υποστηρίζει άμεσα αρχεία — πρέπει να κωδικοποιηθούν σε base64.
Το πρωτόκολλο 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/form-data υποστηρίζει πολλά αρχεία σε ένα αίτημα. Κάθε αρχείο μεταδίδεται ως ξεχωριστό τμήμα με δικό του Content-Disposition και Content-Type. Οι φόρμες HTML χρησιμοποιούν το χαρακτηριστικό multiple για input type="file". Στο OkHttp, καλείται addFormDataPart για κάθε αρχείο, στο Alamofire — append για κάθε αρχείο.
Boundary είναι μια μοναδική συμβολοσειρά που διαχωρίζει τα τμήματα ενός σύνθετου αιτήματος και επιτρέπει στον διακομιστή να προσδιορίσει πού τελειώνει ένα τμήμα και πού αρχίζει το επόμενο. Παράγεται από τον πελάτη και καθορίζεται στην κεφαλίδα Content-Type. Χωρίς boundary, ο διακομιστής δεν μπορεί να διαχωρίσει ένα πολυσυστατικό αίτημα σε μεμονωμένα πεδία και αρχεία.
Μην βασίζεστε στην επέκταση αρχείου ή στο Content-Type από το αίτημα — ένας εισβολέας μπορεί να τα παραποιήσει. Ελέγξτε τον τύπο MIME μέσω magic bytes (πρώτα byte του αρχείου): βιβλιοθήκες Apache Tika σε Java, libmagic σε C/C++, εντολή file σε Linux, ή ενσωματωμένα εργαλεία πλαισίων — Files.probeContentType() σε Java, mimetypes σε Python.
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης