Example of Multipart/Form-Data

What does enctype='multipart/form-data' mean?

When you make a POST request, you have to encode the data that forms the body of the request in some way.

HTML forms provide three methods of encoding.

  • application/x-www-form-urlencoded (the default)
  • multipart/form-data
  • text/plain

Work was being done on adding application/json, but that has been abandoned.

(Other encodings are possible with HTTP requests generated using other means than an HTML form submission. JSON is a common format for use with web services and some still use SOAP.)

The specifics of the formats don't matter to most developers. The important points are:

  • Never use text/plain.

When you are writing client-side code:

  • use multipart/form-data when your form includes any <input type="file"> elements
  • otherwise you can use multipart/form-data or application/x-www-form-urlencoded but application/x-www-form-urlencoded will be more efficient

When you are writing server-side code:

  • Use a prewritten form handling library

Most (such as Perl's CGI->param or the one exposed by PHP's $_POST superglobal) will take care of the differences for you. Don't bother trying to parse the raw input received by the server.

Sometimes you will find a library that can't handle both formats. Node.js's most popular library for handling form data is body-parser which cannot handle multipart requests (but has documentation that recommends some alternatives which can).


If you are writing (or debugging) a library for parsing or generating the raw data, then you need to start worrying about the format. You might also want to know about it for interest's sake.

application/x-www-form-urlencoded is more or less the same as a query string on the end of the URL.

multipart/form-data is significantly more complicated but it allows entire files to be included in the data. An example of the result can be found in the HTML 4 specification.

text/plain is introduced by HTML 5 and is useful only for debugging — from the spec: They are not reliably interpretable by computer — and I'd argue that the others combined with tools (like the Network Panel in the developer tools of most browsers) are better for that).

What is the right way to POST multipart/form-data using curl?

The following syntax fixes it for you:

curl -v -F key1=value1 -F upload=@localfilename URL

How to send multipart/form-data request using Postman

UPDATE: I have created a video on sending multipart/form-data requests to explain this better.


Actually, Postman can do this.

Sample Image

Full example:

Sample Image

You DON'T need to add any headers, Postman will do this for you automatically.

Sample Image

Make sure you check the comment from @maxkoryukov

Be careful with explicit Content-Type header. Better - do not set it's
value, the Postman is smart enough to fill this header for you. BUT,
if you want to set the Content-Type: multipart/form-data - do not
forget about boundary field.

405 Error : multipart/form-data with Spring

This was the solution that I found from Antonio112009's answer

SOLUTION

@PostMapping(value = "/submitForm")
public ResponseEntity<?> userRegistration(
@RequestParam("user") String user,
@RequestParam(value = "files", required = false) List<MultipartFile> files) {

ObjectMapper obj = new ObjectMapper();
User user = new User();
.
.
.
}

POST data using the Content-Type multipart/form-data

Here's some sample code.

In short, you'll need to use the mime/multipart package to build the form.

package main

import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"net/http/httputil"
"os"
"strings"
)

func main() {

var client *http.Client
var remoteURL string
{
//setup a mocked http client.
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := httputil.DumpRequest(r, true)
if err != nil {
panic(err)
}
fmt.Printf("%s", b)
}))
defer ts.Close()
client = ts.Client()
remoteURL = ts.URL
}

//prepare the reader instances to encode
values := map[string]io.Reader{
"file": mustOpen("main.go"), // lets assume its this file
"other": strings.NewReader("hello world!"),
}
err := Upload(client, remoteURL, values)
if err != nil {
panic(err)
}
}

func Upload(client *http.Client, url string, values map[string]io.Reader) (err error) {
// Prepare a form that you will submit to that URL.
var b bytes.Buffer
w := multipart.NewWriter(&b)
for key, r := range values {
var fw io.Writer
if x, ok := r.(io.Closer); ok {
defer x.Close()
}
// Add an image file
if x, ok := r.(*os.File); ok {
if fw, err = w.CreateFormFile(key, x.Name()); err != nil {
return
}
} else {
// Add other fields
if fw, err = w.CreateFormField(key); err != nil {
return
}
}
if _, err = io.Copy(fw, r); err != nil {
return err
}

}
// Don't forget to close the multipart writer.
// If you don't close it, your request will be missing the terminating boundary.
w.Close()

// Now that you have a form, you can submit it to your handler.
req, err := http.NewRequest("POST", url, &b)
if err != nil {
return
}
// Don't forget to set the content type, this will contain the boundary.
req.Header.Set("Content-Type", w.FormDataContentType())

// Submit the request
res, err := client.Do(req)
if err != nil {
return
}

// Check the response
if res.StatusCode != http.StatusOK {
err = fmt.Errorf("bad status: %s", res.Status)
}
return
}

func mustOpen(f string) *os.File {
r, err := os.Open(f)
if err != nil {
panic(err)
}
return r
}

Empty $request- request and $request- files with multipart/form-data

DO NOT specify the Content-Type header yourself, when trying to make such a multipart request. That header needs to include the boundary value (so that the receiver will know how to parse this request) - if you specify it yourself, as just multipart/form-data, then that will be missing.

These request libraries usually know how to properly set it on their own, based on that you are passing in a FormData instance.

Why not use enctype= multipart/form-data always?

From the RFC that defines multipart/form-data:

Many web applications use the "application/x-www-form-urlencoded"
method for returning data from forms. This format is quite compact,
for example:

name=Xavier+Xantico&verdict=Yes&colour=Blue&happy=sad&Utf%F6r=Send

However, there is no opportunity to label the enclosed data with a
content type, apply a charset, or use other encoding mechanisms.

Many form-interpreting programs (primarily web browsers) now
implement and generate multipart/form-data, but a receiving
application might also need to support the
"application/x-www-form-urlencoded" format.

Aside from letting you upload files, multipart/form-data also allows you to use other charsets and encoding mechanisms. So the only reasons not to use it are:

  • If you want to save a bit of bandwidth (bearing in mind that this becomes much less of an issue if the request body is compressed).

  • If you need to support really old clients that can't handle file uploads and only know application/x-www-form-urlencoded, or that have issues handling anything other than ASCII.

Get key-value pairs from multipart/form-data HTTP POST request in Camel

For the sake of clarity, as the proposed solution here above seems to work, a bit more explanations (although it is more a workaround than a solution):

Starting from:

Map<String, Attachment> attachmentObjects = attachmentMessage.getAttachmentObjects();

It is possible to browse all map entries, and for each found Attachment object, examine the attachment headers using getHeaderNames(), among other the 'Content-Disposition' one:

Content-Disposition: form-data; name="data"; filename="data-file.json"

which can finally be parsed to grab the form name ('data' in this example).

Not straightforward true, but this apparently works...



Related Topics



Leave a reply



Submit