Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get browser to prompt user to save a file dynamically generated by server?

Clients submit post requests using jquery ajax as illustrated below:

$.ajax({
    url: "/xxx?request1", 
    data: theParams,
    type: 'post',
    error: function(XMLHttpRequest, textStatus, errorThrown){
        // error handling
    },
    success: function(data){
    var theResult = JSON.parse(data);
        // success handling
    }
});

Apache is configured to pass requests with /xxx? to a custom app. The app processes the request and returns information. Usually, this information returned as JSoN and is displayed in the "success handling" section, using jquery/javascript. The app writes the following headers (which are then returned via apache) prior to writing the JSON:

HTTP/1.0 200 OK
Connection: close
Server: MyServer v. 0.826
Content-Type: text/html

I also have cookies working by placing the following right after the 200 OK line:

Set-Cookie: cookie_name=value; Domain=example.com; Path=/; Expires=Fri, 21-Mar-2014 01:40:22 GMT; HttpOnly

In one scenario, I'd like the user to be able to save the returned data (as a plain text file). But here is where I run into problems.

If I use JavaScript to open a window and write the data to the new window, I've found that Safari and Chrome both disable the "Save as..." menu option (on Macs).

(I have got a version working by using base64 URI, but that looks unpolished relative to the rest of the site.)

I then began trying to include a Content-Disposition: attachment; filename=file.txt header but I could never get the browser to produce a prompt. I tried placing this header right after the 200 OK line, as well as later:

Content-Type: text/plain
Content-Disposition: attachment; filename=file.txt

In addition to being not sure of the exact format of the Content-Disposition header, I'm also not sure if I have the Content-Type correct or if there's something in the ajax handler code that is preventing the save.

I've tried to find examples where everything is put together, but can only find parts and clearly I can't get it put together correctly. Any suggestions?

I'm targeting only modern browsers, three major platforms (Mac/Windows/Linux), and only HTML5/JavaScript on the client side.

like image 411
RPW Avatar asked Dec 21 '13 02:12

RPW


1 Answers

Content-Disposition: attachment is the right header, but the browser only obeys it when loading the file directly. Using AJAX (even through jQuery) will not work.

There is a way to do this. Read the full explanation in this answer, but basically you just have to write that in your success function:

window.location = "data:application/octet-stream," + encodeURIComponent(theResult);

Edit: FileSaver.js provides a wrapper improving browser compatibility and adding support for filenames for compatible browsers:

var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
saveAs(blob, "hello world.txt");
like image 98
1ace Avatar answered Sep 25 '22 10:09

1ace