Respond to an XHR POST with a binary file

I've been experimenting with new-ish browser features and one that I've wanted to write about for a while is receiving a binary response (a file) as a response to an XHR POST. jQuery can't do this so the first thing to do is figure it out using plain javascript.

The general use case for this is: send some data to a service, let the service do something with the data, get a file from the service that incorporates the data. More specifically, I've needed to send data from a form to a service and get back a PDF file with info from the form. Before figuring out how to do this by receiving an arraybuffer, the workflow was to make a service respond with a URL to a file someone could download. That works, but it has the downside of requiring file storage on a server and, more importantly, an additional click to download a file.

Before I could show an example of how this works, I needed a simple service that could receive a POST and send back a file. I put together a simple express app that does just that. The code is on github and relies on handlebars and the html-pdf module from NPM in addition to express.

The important part of server.js is in the end callback from html-pdf's toStream method. The file is assembled as a Buffer, a couple of headers are set and the response is sent.

But I'm getting ahead of myself. To run this locally, clone the repo. Run npm install, npm run start and load http://localhost:3007/form.html. Clicking the submit button will send data to the locally running service and it will send back a PDF which your browser will download.

The client side piece is in xhr-binary.js. When the form is submitted, a new xhr is created and the responseType is set to arraybuffer. Once the xhr loads, a Blob is created and FileServer's saveAs method is used to coax the browser into saving the file locally. There's also a loading spinner that gets displayed while node/express/html-pdf/phantomjs do their thing to create the PDF.