application/x-www-form-urlencoded ή multipart/form-data?

Στο HTTP υπάρχουν δύο τρόποι για την αποστολή δεδομένων POST: application/x-www-form-urlencoded και multipart/form-data. Καταλαβαίνω ότι οι περισσότεροι φυλλομετρητές είναι σε θέση να ανεβάσουν αρχεία μόνο εάν χρησιμοποιείται η μορφή multipart/form-data. Υπάρχει κάποια πρόσθετη καθοδήγηση για το πότε πρέπει να χρησιμοποιείται ένας από τους τύπους κωδικοποίησης σε ένα πλαίσιο API (χωρίς να εμπλέκεται πρόγραμμα περιήγησης); Αυτό θα μπορούσε π.χ. να βασίζεται σε:

  • μέγεθος δεδομένων
  • ύπαρξη μη ASCII χαρακτήρων
  • ύπαρξη (μη κωδικοποιημένων) δυαδικών δεδομένων
  • την ανάγκη μεταφοράς πρόσθετων δεδομένων (όπως το όνομα αρχείου)

Βασικά δεν βρήκα καμία επίσημη καθοδήγηση στο διαδίκτυο σχετικά με τη χρήση των διαφόρων τύπων περιεχομένου μέχρι στιγμής.

Λύση

TL;DR

Σύνοψη: αν έχετε να μεταδώσετε δυαδικά (μη αλφαριθμητικά) δεδομένα (ή ωφέλιμο φορτίο σημαντικού μεγέθους), χρησιμοποιήστε το multipart/form-data. Διαφορετικά, χρησιμοποιήστε application/x-www-form-urlencoded.


Οι τύποι MIME που αναφέρετε είναι οι δύο επικεφαλίδες Content-Type για αιτήσεις HTTP POST που πρέπει να υποστηρίζουν οι πράκτορες-χρήστες (browsers). Ο σκοπός και των δύο αυτών τύπων αιτήσεων είναι η αποστολή μιας λίστας ζευγών ονόματος/τιμής στον διακομιστή. Ανάλογα με τον τύπο και την ποσότητα των δεδομένων που μεταδίδονται, η μία από τις μεθόδους θα είναι πιο αποτελεσματική από την άλλη. Για να καταλάβετε το γιατί, πρέπει να εξετάσετε τι κάνει η καθεμία από αυτές κάτω από τα καλύμματα.

Για την application/x-www-form-urlencoded, το σώμα του μηνύματος HTTP που αποστέλλεται στον διακομιστή είναι ουσιαστικά ένα τεράστιο αλφαριθμητικό ερωτήματος -- τα ζεύγη ονόματος/τιμής διαχωρίζονται με την τελεία και παύλα (&) και τα ονόματα διαχωρίζονται από τις τιμές με το σύμβολο ισότητας (=). Ένα παράδειγμα θα ήταν:&nbsp,

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

Σύμφωνα με τις προδιαγραφές:

Οι μη αλφαριθμητικοί χαρακτήρες αντικαθίστανται από `%HH', ένα σύμβολο του ποσοστού και δύο δεκαεξαδικά ψηφία που αντιπροσωπεύουν τον κωδικό ASCII του χαρακτήρα.

Αυτό σημαίνει ότι για κάθε μη αλφαριθμητικό byte που υπάρχει σε μια από τις τιμές μας, θα χρειαστούν τρία bytes για να το αναπαραστήσουμε. Για μεγάλα δυαδικά αρχεία, ο τριπλασιασμός του ωφέλιμου φορτίου θα είναι εξαιρετικά αναποτελεσματικός.

Σε αυτό το σημείο έρχεται το multipart/form-data. Με αυτή τη μέθοδο μετάδοσης ζευγών ονόματος/τιμής, κάθε ζεύγος αναπαρίσταται ως ένα "μέρος" σε ένα μήνυμα MIME (όπως περιγράφεται σε άλλες απαντήσεις). Τα μέρη διαχωρίζονται από ένα συγκεκριμένο όριο συμβολοσειράς (που επιλέγεται ειδικά έτσι ώστε αυτή η οριακή συμβολοσειρά να μην εμφανίζεται σε κανένα από τα ωφέλιμα φορτία "value"). Κάθε μέρος έχει το δικό του σύνολο επικεφαλίδων MIME, όπως Content-Type, και ιδιαίτερα Content-Disposition, οι οποίες μπορούν να δώσουν σε κάθε μέρος το "όνομά του."Το κομμάτι αξίας κάθε ζεύγους ονόματος/τιμής είναι το ωφέλιμο φορτίο κάθε μέρους του μηνύματος MIME. Το MIME spec μας δίνει περισσότερες επιλογές κατά την αναπαράσταση του ωφέλιμου φορτίου τιμών -- μπορούμε να επιλέξουμε μια πιο αποδοτική κωδικοποίηση δυαδικών δεδομένων για να εξοικονομήσουμε εύρος ζώνης (π.χ. base 64 ή ακόμα και raw binary).

Γιατί να μην χρησιμοποιείτε πάντα το multipart/form-data; Για σύντομες αλφαριθμητικές τιμές (όπως οι περισσότερες φόρμες ιστού), η επιβάρυνση από την προσθήκη όλων των επικεφαλίδων MIME πρόκειται να υπερκαλύψει σημαντικά οποιαδήποτε εξοικονόμηση από την αποδοτικότερη δυαδική κωδικοποίηση.

Σχόλια (16)

Δεν νομίζω ότι το HTTP περιορίζεται σε POST σε multipart ή x-www-form-urlencoded. Η επικεφαλίδα [Content-Type Header][1] είναι ορθογώνια για τη μέθοδο HTTP POST (μπορείτε να συμπληρώσετε τον τύπο MIME που σας ταιριάζει). Αυτό ισχύει και για τις τυπικές διαδικτυακές εφαρμογές που βασίζονται στην αναπαράσταση HTML (π.χ. το json payload έγινε πολύ δημοφιλές για τη μετάδοση του ωφέλιμου φορτίου για αιτήματα ajax).

Όσον αφορά το Restful API μέσω HTTP, οι πιο δημοφιλείς τύποι περιεχομένου με τους οποίους ήρθα σε επαφή είναι οι application/xml και application/json.

application/xml:

  • data-size: XML πολύ φλύαρο, αλλά συνήθως δεν αποτελεί πρόβλημα όταν χρησιμοποιείται συμπίεση και σκεφτόμαστε ότι η περίπτωση πρόσβασης εγγραφής (π.χ. μέσω POST ή PUT) είναι πολύ πιο σπάνια από την πρόσβαση ανάγνωσης (σε πολλές περιπτώσεις είναι
Σχόλια (3)

Συμφωνώ με πολλά από αυτά που είπε ο Manuel. Στην πραγματικότητα, τα σχόλιά του αναφέρονται σε αυτό το url...

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4

... το οποίο αναφέρει:

Ο τύπος περιεχομένου "application/x-www-form-urlencoded" είναι αναποτελεσματικός για την αποστολή μεγάλων ποσοτήτων δυαδικών δεδομένων ή κειμένου που περιέχει μη ASCII χαρακτήρες. Το τύπος περιεχομένου "multipart/form-data&quot, πρέπει να χρησιμοποιείται για την υποβολή φορμών που περιέχουν αρχεία, δεδομένα μη ASCII, και δυαδικά δεδομένα.

Ωστόσο, για μένα αυτό εξαρτάται από την υποστήριξη εργαλείων/πλαισίων.

  • Ποια εργαλεία και πλαίσια αναμένουν οι χρήστες του API σας να κατασκευάσουν τις εφαρμογές τους;
  • Έχουν πλαίσια ή στοιχεία που μπορούν να χρησιμοποιήσουν που ευνοούν μια μέθοδο έναντι της την άλλη;

Αν έχετε μια σαφή ιδέα για τους χρήστες σας και για το πώς θα χρησιμοποιήσουν το API σας, τότε αυτό θα σας βοηθήσει να αποφασίσετε. Αν κάνετε το ανέβασμα αρχείων δύσκολο για τους χρήστες του API σας, τότε θα απομακρυνθούν, και εσείς θα ξοδέψετε πολύ χρόνο για την υποστήριξή τους.

Δευτερευόντως, θα πρέπει να ληφθεί υπόψη η υποστήριξη των εργαλείων που ΕΣΕΙΣ διαθέτετε για τη συγγραφή του API σας και το πόσο εύκολο είναι για εσάς να προσαρμόσετε τον ένα μηχανισμό μεταφόρτωσης σε σχέση με τον άλλο.

Σχόλια (2)