One of the new features added to XMLHttpRequest
Level 2 (http://www.w3.org/TR/XMLHttpRequest2/) is the FormData
object. This enables us to use a set of key-value pairs that can be sent using AJAX. The most common use is in sending binary files or any other large amount of data. In this recipe, we will create two scripts that will send FormData
, one with a plain JavaScript and the other with jQuery, as well as the server-side code to support it.
The server will be done in Nodejs using restify (http://mcavage.github.io/node-restify/). In order to install the dependencies, a package.json
file can be created where restify will be added.
HTTP POST
with type multipart/form-data
; that is why there is a built-in plugin for restify
called BodyParser
. This will block the parsing of the HTTP request body:var server = restify.createServer(); server.use(restify.bodyParser({ mapParams: false })); server.post('hi', addHeaders, doPost);
application/json
, application/x-ww-form-urlencoded
, and mutipart/form-data
. The addHeaders
parameter will be the same as we added in the other examples that enables CORS. For simplicity in our doPost
handler, we just log the request body and return HTTP 200:function doPost(req, res, next) { console.log("Got HTTP " + req.method + " on " + req.url + " responding"); console.log(req.body); res.send(200); return next(); }
(function (){ var myForm = new FormData(); myForm.append("username", "johndoe"); myForm.append("books", 7); var xhr = new XMLHttpRequest(); xhr.open("POST", "http://localhost:8080/hi"); xhr.send(myForm); }());
jQuery
way is a lot simpler; we can set FormData
as part of the data
attribute in jQuery.ajax()
where additionally we need to disable data processing before we send and leave the original content type:(function(){ var formData = new FormData(); formData.append("text", "some strange data"); $.ajax({ url: "http://localhost:8080/hi", type: "POST", data: formData, processData: false, // don't process data contentType: false // don't set contentType }); }());
The transmitted data will have the same format as it would if we submitted a form that has the multipart/form-data
encoding type. The need for this type of encoding comes from sending mixed data together with files. This encoding is supported by most of the web browsers and web servers. The encoding can be used for forms that are not HTML or even part of the browser.
If we take a look at request being sent, we can see that it has the following data:
Content-Length:239 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryQXGzNXa82frwui6S
The payload will be as follows:
------WebKitFormBoundaryQXGzNXa82frwui6S Content-Disposition: form-data; name="username" johndoe ------WebKitFormBoundaryQXGzNXa82frwui6S Content-Disposition: form-data; name="books" 7 ------WebKitFormBoundaryQXGzNXa82frwui6S--
You may notice that each of these parts contain a Content-Disposition
section with the name of the control that is an origin of the data or, in our case, the key we set in every append to the FormData
object. There is also an option to set the content type on each individual part, for example, if we had an image from some control named profileImage
then that part can be as follows:
Content-Disposition: form-data; name="profileImage"; filename="me.png" Content-Type: image/png
The last call to xhr.sent()
in example.js
sets the content type automatically when we are sending an object of type FormData
.
And if we need to support older legacy browsers that don't have XMLHttpRequest
level 2, we can check if FormData
is there and handle that case accordingly:
if (typeof FormData === "undefined")
The method we use as a fallback cannot be an AJAX call, but this should not be a problem as all the modern browsers IE<10 version don't have support for it.
3.21.46.92