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.