Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File download through ajax

I need to download file from server via ajax. The problem is that the file is not stored on server. My java-based backend automatically generates file from request parameters and returns it in response body:

  @RequestMapping(value = "/download", method = RequestMethod.GET)
  public void download(@RequestParam String description, @RequestParam Long logId, HttpServletResponse response) {
    try {
      InputStream fileContent = // getting file as byte stream
      response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
      response.setHeader("Content-Disposition", "attachment; filename=file.zip");
      ServletOutputStream responseOutputStream = response.getOutputStream();
      org.apache.commons.io.IOUtils.copy(fileContent, responseOutputStream);
      response.flushBuffer();
    } catch (IOException e) {
      logger.error("Attempt to download file failed", e);
    }
  }

So i need to handle it and allow user to download file. My client side contains this:

$.ajax({
  type: "GET",
  url: "/download",
  data: {
    description: "test",
    logId: 123
  },
  success: function(data) {
    var blob = new Blob([data]);
    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = "file.zip";
    link.click();
  }
})

Controller returns file, but then nothing happens. What am i doing wrong?

like image 472
Everv0id Avatar asked Mar 21 '16 14:03

Everv0id


2 Answers

Don't make an AJAX call, but rather set the window's href to point to URL for downloading the file. Then change the content type of the response to application/x-download and set the header of the response to be Content-disposition:

response.setContentType("application/x-download");
response.setHeader("Content-disposition", "attachment; filename=" + fileName);
response.flushBuffer();

function download(fileName) {
    window.location.href = "/download?description=test&logId=123";
}

Also, have a look at this SO post which addresses a similar problem to the one you have.

like image 97
Tim Biegeleisen Avatar answered Oct 08 '22 17:10

Tim Biegeleisen


For those looking a more modern approach, you can use the fetch API. The following example shows how to download a PDF file. It is easily done with the following code.

fetch(url, {
    body: JSON.stringify(data),
    method: 'POST',
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    },
})
.then(response => response.blob())
.then(response => {
    const blob = new Blob([response], {type: 'application/pdf'});
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = downloadUrl;
    a.download = "file.pdf";
    document.body.appendChild(a);
    a.click();
})

I believe this approach to be much easier to understand than other XMLHttpRequest solutions. Also, it has a similar syntax to the jQuery approach, without the need to add any additional libraries.

Of course, I would advise checking to which browser you are developing, since this new approach won't work on IE. You can find the full browser compatibility list on the following [link][1].

Important: In this example I am sending a JSON request to a server listening on the given url. This url must be set, on my example I am assuming you know this part. Also, consider the headers needed for your request to work. Since I am sending a JSON, I must add the Content-Type header and set it to application/json; charset=utf-8, as to let the server know the type of request it will receive.

Important: Sending parameters to a 'GET' request using the fetch API would need to use URLSearchParams interface.

like image 41
Alain Cruz Avatar answered Oct 08 '22 18:10

Alain Cruz