-1

I have a situation where I want to download a large file from my RestFul java backend. The java backend will stream the file in chunks see following code:

    String filePath = this.workProgressService.getFilePath(entityId);
    Path path = Paths.get(filePath);
    FileNameMap fileNameMap = URLConnection.getFileNameMap();
    String mimeType = fileNameMap.getContentTypeFor(path.getFileName().toString());
    if (mimeType == null) {
        mimeType = "application/octet-stream";
    }
    response.setContentType(mimeType);
    response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", path.getFileName().toString()));
    FileCopyUtils.copy(Files.newInputStream(path), response.getOutputStream());

The service is working fine. F.E. when I go in the browser to my restendpoint http://localhost:8080/download a file window popup and I can download the file.

But when I do this from angular with the following code:

        const options = new RequestOptions({responseType: ResponseContentType.Blob});
        return this.authHttp.get(this.configurationService.getApiURL() +  '/filedownload', options)
        .map(response => {
            console.log(response.blob());
        });

The console log of the blob is triggered at the end when the file is completely downloaded. If I watch the request in the developer console of Chrome I can see it download the whole file first before it will log it's response. This way the file save dialog is not opened untill the response is there.

The problem is I can't just use a href to the location of the Rest endpoint because I need to send an authorization header in the GET request.

How can I solve this that the user can download the file with a dialog from the back-end directly and not have to wait till browser has completely downloaded the file?

  • what is the problem? – Mick Mar 14 '18 at 08:36
  • The problem is, that I want the download dialog to be shown directly when user clicks download. Not when the whole request is completed and the 1GB is downloaded in the browsers request. This way there is no progress anymore when the user downloads the file. Also the user things nothing is happening as the request takes very long. – user1547984 Mar 14 '18 at 10:07
  • I guess you need to make sure to get all HTTP headers right and thus help your client. The filename of Content-disposition may only contain ASCII chars. I also recommend adding a Content-length header, since you already know the filesize in advance. This enables the client to render a proper progress. And since the download dialog is a very browser-related thing, please tell which browser you are using and which Angular version. – Mick Mar 14 '18 at 14:58
  • Thank you for your comment. I've added the content-length to the headers. I can also see the correct headers in the response when looking in the developer console. The browser I use is Chrome. But I also tried it with IE 11 and it has the same behaviour. The front-end uses Angular (V4). When I don't create a GET request to the back-end but F.E. do a window.location.href the File Dialog to download is displayed imidiatly. – user1547984 Mar 15 '18 at 07:06
  • Well, if you tell Angular to make a GET request, you will get the response, but the browser will NOT take any action. Makes sense, doesn't it? Otherwise AJAX would not work, but you would see heaps of save dialogs. Initiating a save dialog has been discussed here: https://stackoverflow.com/questions/2897619/using-html5-javascript-to-generate-and-save-a-file, but I guess you try to find a way working with window.location. Usually after the browser authenticated once against a website, it would send the authentication header automatically, right? – Mick Mar 19 '18 at 13:50

1 Answers1

0

The problem is solved. The GET request of angular will trigger the filesaver dialog when the whole get request is completed. When downloading a large file this is not ideal because it will be downloaded in the browsers memory.

Because I have to use an authorization token which normally is in the header I had to create a workaround.

The workaround is indeed using the window.location.href with the RESTful endpoint to download. But before going to this endpoint the restful backend is called to create a short to live token which is valid to download a file. This token is appended to the URL for the location.href.

Now the browser handles the file dialog to save the file on the computer.