JAX-RS file downloads, multiple content types

10,648

Solution 1

You could use application/octet-stream as content type and do the following to download files:

@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadFile(String fileName) {
    File file = ... // Find your file
    return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
        .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"")
        .build();
}

Since you are using JavaScript to download files, have a look here and here.

Solution 2

Fixed it, used the content-type: application/octet-stream. I also added the header mentioned above:

 return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
        .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"")
        .build();

my error was thinking that after an ajax call the file would download in the same window. changed my client side code to do the request in another window using :

window.open(resturl);

the reaction was that the browser would open a new window, download the file into the download tray and return to the webpage in which you clicked download whilst closing the download tab. (in about 0.2 seconds).

Share:
10,648
Mark Stroeven
Author by

Mark Stroeven

Hey there, My name is Mark, I am a full time IT student wanting to specialize in programming. Still learning a lot and thought i could learn a lot from more experienced programmers around here! You will have to excuse me for my bad limited English, I am afraid it is not my native language.

Updated on June 04, 2022

Comments

  • Mark Stroeven
    Mark Stroeven almost 2 years

    Let me provide some context first. I am working on a system that integrates with Microsoft SharePoint 2010, well not really SharePoint as a system but the virtual representation of it's filesystem, document libraries, etc... Users upload files to SharePoint, and my system monitors these files and indexes them into a search engine (including file content). User can interact with this system by means of REST interfaces.

    I have created a REST interface to fetch a file for the user corresponding a certain entry in my search engine. This uses the absolute network path as its identifier. An example would be //corporateserver//library1/filex.docx. Due to the same origin policy however I can not load this file client side. Therefore I am trying to transmit it via the server.

    I had some success using JAX-RS to transmit data, however, I am getting stuck at the following:

    The file the user wishes to download can be of mutliple content types, most of them will be microsoft office formats. I had a look through the list of registered MIME types and came across application/msword or application/vnd.ms-powerpoint

    My question: is there a content type that would include Microsoft Office files? If not, how could one proceed to match the correct content types with a file that is being requested. What would happen if one would server a word file with content type text/plain?

    Any help on the subject would be greatly appreciated.

    EDIT

    The code I use to transmit data:

    package com.fujitsu.consensus.rest;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.QueryParam;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.core.StreamingOutput;
    
    import org.apache.commons.io.IOUtils;
    import org.codehaus.jettison.json.JSONException;
    
    @Path("/fetcher")
    public class FetcherService {
    
        @GET
        @Path("/fetch")
        @Produces(MediaType.APPLICATION_OCTET_STREAM)
        public Response fetchFile(@QueryParam("path") String path) 
            throws JSONException, IOException {
    
            final File file = new File(path);
            System.out.println(path);
    
            StreamingOutput stream = new StreamingOutput() {
                @Override
                public void write(OutputStream output) throws IOException {
                    try {
                        output.write(IOUtils.toByteArray(new FileInputStream(file)));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
    
            return Response.ok(stream, MediaType.APPLICATION_OCTET_STREAM)
                .header("Content-Disposition", "inline; filename=\"" + file.getName() + "\"") 
                .build();
        }
    }
    

    JavaScript code:

     $.ajax({
       url: "../rest/fetcher/fetch",
       type: "GET", //send it through get method
       data:{path:obj.id},
       success: function(response) {
       console.log(response);},
       error: function(xhr) {//Do Something to handle error}
     });
    

    The response I get on client side:

    response on client side

    EDIT 2

    I've added a HTTP trace as proof that the headers and data are in fact being transmitted, the download dialogue however is not shown.

    The Content-Disposition header does not appear to be working with either inline or attachment.

    HTTP trace result

  • Mark Stroeven
    Mark Stroeven over 8 years
    added some more info, came a bit further but still not working as intended with the code example provided.
  • cassiomolin
    cassiomolin over 8 years
    @MarkStroeven The response seems fine, since you are downloading a file. The problem might be in the JavaScript you are using. For test purposes, try using GET instead of POST, send the file name as a query or path parameter and type the URL in the browser instead of using JavaScript.
  • cassiomolin
    cassiomolin over 8 years
    @MarkStroeven Have a look at my updated answer about downloading files with JavaScript.
  • Mark Stroeven
    Mark Stroeven over 8 years
    Tried both of the threads you linked :) both are giving the error "Not allowed to load local resource" both server and client are actually on the same corporate domain.
  • cassiomolin
    cassiomolin over 8 years
    @MarkStroeven Can you download the file using GET and typing the URL in the browser address bar?
  • Mark Stroeven
    Mark Stroeven over 8 years
    Tested it using the file location as a parameter with a get request. I fetches the data, if I print it you see the encoded data again. Its not prompting a download screen. Same thing when I enter it manually.