Thursday, July 17, 2008

Pushing files from Javascript

How can I get some content from javascript (like a string) and send it to the client as a file? I don't have access to the content I want to send from the server.

This was a question posed to me in a rather more complex way: how do I take some file content from a web service and send it to the client as as file without downloading the content to the web server first?

The simple answer right now: you cannot do it. If you guys know more about this, please let me know. I've exausted all avenues I could think of, but then again, I am no master of Javascript and html responses.

Here is what I have tried. Basically, I have a string like a html table and I want it sent to the client browser as an excel download. So I opened a new window with javascript and tried to write the content there:

It worked and it displayed a table. Now, all I wanted to do is add/change the html header content-type to application/ Apparently, you can't do it from Javascript. Ok, how about getting the necessary headers from the ASP.Net server? (remember, the restriction was that only the file content should not come from the web server). So I created a new page that would render a completely empty page with the right headers:

protected void Page_Load(object sender, EventArgs e)
Response.Buffer = true;
Response.ContentType = "application/";
Response.AppendHeader("Content-Disposition", "attachment;filename=test.xls");
Response.Charset = "";


Then I just opened it in a new window (just ignore the browser pop-up filters for now) with

What happened was that the page was just rendered like a normal page. How come? I change the code so that it would write the content after a few seconds. And I got this: first the browser asks me if I want to permit downloading the file, then, after a few seconds, the warning goes away and the string is displayed in the new window. I tried with document.createTextNode, it didn't work.

So far, none of my attempts to serve javascript content as a binary file worked. If you know of a way to achieve this, please let me know. Thanks!

Meaflux took a swipe at this request and came up with two delicious ideas that, unfortunately, don't really work. But I had no idea things like these existed, so it is very much worth mentioning.

First: the data URI. Unfortunately it is only supported by FireFox and such and has no way of setting a content-disposition header or some other way of telling the browser that I actually want it saved. It would work for an excel file, but an image, for example, would be opened in a browser window.

Second: the IE execCommand javascript function which has a little command called SaveAs. Unfortunately this would only work for actual HTML pages. Even if the browser would open a binary file, I doubt that a saveAs command would save it correctly.

Besides, both these options, as well as my own attempts above, have a major flaw: there is no way to send chunks of data as you are receiving them from the web service. What is needed it declaring some sort of data stream, then writing stuff in it and then declaring it programatically closed.