Localizations

Introduction

One of the unsung heros in the HTML5 universe is XMLHttpRequest.
Strictly speaking XHR2 isn't HTML5. However, it's part of the incremental improvements
browser vendors are making to the core platform. I'm including XHR2 in our new bag of
goodies because it plays such an integral part in today's complex web apps.

Turns out our old friend got a huge makeover but many folks
are unaware of its new features. XMLHttpRequest Level 2
introduces a slew of new capabilities which put an end to crazy hacks in our web apps;
things like cross-origin requests, uploading progress events,
and support for uploading/downloading binary data. These allow AJAX
to work in concert with many of the bleeding edge HTML5 APIs such as File System API,
Web Audio API,
and WebGL.

This tutorial highlights some of the new features in XMLHttpRequest,
especially those that can be used for working with files.

Fetching data

Fetching a file as a binary blob has been painful with XHR. Technically,
it wasn't even possible. One trick that has been well documented involves
overriding the mime type with a user-defined charset as seen below.

While this works, what you actually get back in the responseText
is not a binary blob. It is a binary string representing the image file.
We're tricking the server into passing the data back, unprocessed.
Even though this little gem works, I'm going to call it black magic and advise
against it. Anytime you resort to character code hacks and string manipulation
for coercing data into a desirable format, that's a problem.

Specifying a response format

In the previous example, we downloaded the image as a binary "file"
by overriding the server's mime type and processing the response text as a binary string.
Instead, let's leverage XMLHttpRequest's new
responseType and response properties to inform
the browser what format we want the data returned as.

xhr.responseType

Before sending a request, set the xhr.responseType
to "text", "arraybuffer", "blob", or "document", depending on your data needs.
Note, setting xhr.responseType = '' (or omitting) will default
the response to "text".

xhr.response

After a successful request, the xhr's response property will
contain the requested data as a DOMString, ArrayBuffer,
Blob, or Document (depending on what was set for
responseType.)

With this new awesomeness, we can rework the previous example, but this time,
fetch the image as an Blob instead of a string:

ArrayBuffer responses

An ArrayBuffer
is a generic fixed-length container for binary data. They are super handy if you
need a generalized buffer of raw data, but the real power behind these guys is that
you can create "views" of the underlying data using JavaScript typed arrays.
In fact, multiple views can be created from a single ArrayBuffer source.
For example, you could create an 8-bit integer array that shares the same ArrayBuffer
as an existing 32-bit integer array from the same data. The underlying data
remains the same, we just create different representations of it.

As an example, the following fetches our same image as an ArrayBuffer,
but this time, creates an unsigned 8-bit integer array from that data buffer:

Sending data

Being able to download data in different formats is great, but it doesn't
get us anywhere if we can't send these rich formats back to home base (the server).
XMLHttpRequest has limited us to sending DOMString
or Document (XML) data for some time. Not anymore. A revamped send()
method has been overridden to accept any of the following types:
DOMString, Document, FormData, Blob,
File, ArrayBuffer. The examples in the rest of this
section demonstrate sending data using each type.

There's nothing new here, though the right snippet is slightly different.
It sets responseType='text' for comparison. Again, omitting that line
yields the same results.

Submitting forms: xhr.send(FormData)

Many people are probably accustomed to using jQuery plugins
or other libraries to handle AJAX form submissions. Instead, we can use FormData,
another new data type conceived for XHR2. FormData
is convenient for creating an HTML <form> on-the-fly, in JavaScript.
That form can then be submitted using AJAX:

An HTML form can include file uploads (e.g. <input type="file">)
and FormData can handle that too. Simply append the file(s) and the browser will
construct a multipart/form-data request when send() is called:

Cross Origin Resource Sharing (CORS)

CORS allows web applications
on one domain to make cross domain AJAX requests to another domain.
It's dead simple to enable, only requiring a single response header to be sent by the server.

Enabling CORS requests

Let's say your application lives on example.com and you
want to pull data from www.example2.com. Normally if you
tried to make this type of AJAX call, the request would fail and the browser
would throw an origin mismatch error. With CORS, www.example2.com
can choose to allow requests from example.com by simply adding a header:

Access-Control-Allow-Origin: http://example.com

Access-Control-Allow-Origin can be added to a single resource
under a site or across the entire domain. To allow any domain to make
a request to you, set:

Access-Control-Allow-Origin: *

In fact, this site (html5rocks.com) has enabled CORS on all of its pages. Fire up
the Developer Tools and you'll see the Access-Control-Allow-Origin
in our response:

Making a cross-domain request

If the server endpoint has enabled CORS, making the cross-origin request
is no different than a normal XMLHttpRequest request. For example,
here is a request example.com can now make to
www.example2.com:

Practical examples

Download + save files to the HTML5 file system

Let's say you have an image gallery and want to fetch a bunch
of images then save them locally using the HTML5 File System.
One way to accomplish this would be to request images as Blobs
and write them out using FileWriter:

Slicing a file and uploading each portion

Using the File APIs, we can minimize
the work to upload a large file. The technique is to slice the upload into multiple chunks,
spawn an XHR for each portion, and put the file together on the server. This is
similar to how GMail uploads large attachments so quickly. Such a technique could also be
used to get around Google App Engine's 32MB http request limit.