Pet project challenge of the day. I have a REST API that delivers a JSON response, and I want it to include file data, so the browser at the client end can download the file. In real world what I’m doing is offering a link to the user to export some data to an XLS and download to their desktop.
I messed around with this for a while. Carriage of the file data seemed simple – at the REST end encode it to base64 and stick that into the JSON. The problem lies at the client end. I have JQuery calling the REST, and dealing with the response. How then to get the base64 out of the JSON and contrive to offer it as a File Save As situation?
Finally here’s what I came up with, it was sparked by something I saw on StackOverflow, although I cannot lay my hands on the post right now:
At the REST, encode the XLS file text to base64, and return the base64 in the JSON as a text element
On the client, I have an ASP script that acts as the controller, it receives requests from the pages (eg JQuery calls this page), then it calls the remote REST, and returns the response back to JQuery. Obviously cross-browser rules means my JQuery can only call URLs on the same domain, and my REST is not. So this script acts as the transporter for the calls. It’s even called Frank.
On the page I have a form with a hidden field, JQuery puts the base64 file data into that hidden field, then submits the form to another page.
<form id="base64Form" action="openFileToBrowser.asp" method="post" name="base64Form"> <input id="base64data" type="hidden" name="base64data" value="" /> <input id="fileName" type="hidden" name="fileName" value="responses.xls" /> </form>
This new page grabs the file data, decodes it from base64 back to text, sets the content headers to XLS etc. And hey presto, the user gets a File Save As dialog. Here’s the code on that page:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%> <% Option Explicit%> <% response.expires = 0 %> <!--#include virtual="/includes/hex_sha1_base64.asp" --> <% dim base64data base64data=request.form("base64data") if base64data<>"" then Response.ContentType = "application/vnd.ms-excel" Response.AddHeader "Content-Disposition", "attachment; filename="&request.form("fileName") response.write Base64_Decode(base64data) response.Flush() end if %>
The base64 encode/decode routine I’m using is part of the very handy hex_sha1_base64.asp file which I also use for other encryption and encoding tasks (for example I use it for encryption as part of talking to OAUTH based APIs).
I haven’t tested this in all browsers yet, be interesting to see if kicks up problems with IE etc.