In HTTP there are two ways to POST data: application/x-www-form-urlencoded and multipart/form-data . I understand that most browsers are only able to upload files if multipart/form-data is used. Is there any additional guidance when to use one of the encoding types in an API context (no browser involved)? This might e.g. be based on.

  • data size
  • existence of non-ASCII characters
  • existence on (unencoded) binary data
  • the need to transfer additional data (like filename)

So far i've found no formal guidance on the web in regards to the use of different content types

Best Answer


TL;DR

Summary; if you have binary (non-alphanumeric) data (or a significantly sized payload) to transmit, use multipart/form-data . Otherwise, use application/x-www-form-urlencoded .


The MIME types you mention are the two Content-Type headers for HTTP POST requests that user-agents (browsers) must support. The purpose of these two types of requests is to send to the server a list of namevalue pairs Depending on the type and amount of data being transmitted, one of the methods will be more efficient than the other. To understand why, you have to look at what each is doing under the covers.

For application/x-www-form-urlencoded , the body of the HTTP message sent to the server is essentially one giant query string -- name/value pairs are separated by the ampersand ( & ), and names are separated from values by the equals symbol ( = ). An example of this would be:

MyVariableOne=ValueOne&MyVariableTwo=ValueTwo

According to the specification .

[Reserved and] non-alphanumeric characters are replaced by `%HH', a percent sign and two hexadecimal digits representing the ASCII code of the character

That means that for each non-alphanumeric byte that exists in one of our values it will take three bytes to represent it For large binary files, tripling the payload is going to be highly inefficient.

That's where multipart/form-data comes in. With this method of transmitting name-value pairs each pair is represented as a part of a mime message as described by other answers Parts are separated by a specific string boundary chosen specifically so that the boundary string does not exist in any of the value payloads Each part has its own set of MIME headers like Content-Type , and particularly Content-Disposition , which can give each part its "name." The value of each namevalue pair is the payload of each part of the mime message The MIME spec gives us more options when representing the value payload -- we can choose a more efficient encoding of binary data to save bandwidth (e.g. base 64 or even raw binary).

Why not use multipart/form-data all the time? For short alphanumeric values like most web forms the overhead of adding all the mime headers will significantly outweigh any savings from more efficient binary encoding