3

download any file using ResponseEntity with angular does not work

I need to download a file using angular in client side, this file can have any format it could be a pdf or excel or image or txt ... my method works just for txt files and gives me a fail format for excel and image and for the pdf it gives an empty pdf.

so in my controller here is the function that calles the service method:

    vm.downloadFile = downloadFile;

    function downloadFile(file){
        var urlDir = "C://STCI//"+idpeticion;
        return VerDocServices.downloadFile(file,urlDir)
          .then(function(response) {
            var data = response.data;
            var filename = file;
            var contentType = 'application/octet-stream';//octet-stream             
            var linkElement = document.createElement('a');
            try {
                var blob = new Blob([ data ], {
                    type : contentType
                });
                var url = window.URL.createObjectURL(blob);
                linkElement.setAttribute('href', url);
                linkElement.setAttribute("download", filename);
                var clickEvent = new MouseEvent("click", {
                    "view" : window,
                    "bubbles" : true,
                    "cancelable" : false
                });
                linkElement.dispatchEvent(clickEvent);
            } catch (ex) {
                console.log(ex);
                throw ex;
            }
        }).catch(function(response) {
            alert('Se ha producido un error al exportar del documento');
            console.log(response.status);
            throw response;
        });
    }

and my service.js has:

angular.module('mecenzApp').service('VerDocServices',['$http',function($http) {

this.downloadFile = function(file,urlDir) {

    return $http.get('api/downloadFile', {
        params : {
            file : file,
            urlDir : urlDir
        }
    }); }} ]);

And my service method is this:

@GetMapping("/downloadFile")
@Timed
public ResponseEntity<byte[]> downloadFile(@RequestParam(value = "file") String file, @RequestParam(value = "urlDir") String urlDir) {
    log.debug("GET ---------------- DOWNLOAD FILE : {}", file);
    log.debug("GET ---------------- From the DIRECTORY: {}",urlDir);

    InputStream fileStream;
    String filepath = urlDir+File.separator+file;
    try {
        File f = new File(filepath);
        log.debug("GET ---------------- FILE: {}",f.getPath());
        fileStream = new FileInputStream(f);
        byte[] contents = IOUtils.toByteArray(fileStream);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/octet-stream"));   
        String filename = file;
        headers.setContentDispositionFormData(filename, filename);
        ResponseEntity<byte[]> response2 = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
        fileStream.close();
        return response2;            
        
    } catch (FileNotFoundException e) {
       System.err.println(e);
    } catch (IOException e) {
        System.err.println(e);
    }
   return null;
}

could you plz take a look and tell me what did I have missed??

Thank youuu :)

2 Answers 2

6

How to Download Binary Files with AngularJS

When downloading binary files, it is important to set the responseType:

app.service('VerDocServices',['$http',function($http) {

    this.downloadFile = function(url, file, urlDir) {
        var config = {
            //SET responseType
            responseType: 'blob',
            params : {
                file : file,
                urlDir : urlDir
            }
         };

        return $http.get(url, config)
          .then(function(response) {
            return response.data;
        }).catch(function(response) {
            console.log("ERROR: ", response.status);
            throw response;
        }); 
    }; 
}]);

If the responseType is omitted the XHR API defaults to converting UTF-8 encoded text to DOMString (UTF-16) which will corrupt PDF, image, and other binary files.

For more information, see MDN Web API Reference - XHR ResponseType

Sign up to request clarification or add additional context in comments.

1 Comment

you are just AMAZINNNG ! thank youuuuuuuuuuuuuuuuu :D
3

I don't know much about the backend, but I'll provide what i have used may be it will help, so On the Java Script File:

//your $http(request...)

.success(function (data, status, headers, config) {
  //Recieves base64 String data
  var fileName = 'My Awesome File Name'+'.'+'pdf';

  //Parsing base64 String...
  var binaryString =  window.atob(data);
  var binaryLen = binaryString.length;
  var fileContent = new Uint8Array(binaryLen);
  for (var i = 0; i < binaryLen; i++)        {
     var ascii = binaryString.charCodeAt(i);
     fileContent[i] = ascii;
  }
  var blob = new Blob([fileContent], { type: 'application/octet-stream' }); //octet-stream
  var fileURL = window.URL.createObjectURL(blob);
  $sce.trustAsResourceUrl(fileURL);  //allow angular to trust this url
  //Creating the anchor download link
  var anchor = angular.element('<a/>');
  anchor.css({display: 'none'}); // Make sure it's not visible
  angular.element(document.body).append(anchor); // Attach it to the document
  anchor.attr({
    href: fileURL,
    target: '_blank',
    download: fileName
  })[0].click();
  anchor.remove(); // Clean it up afterwards
})
//.error(function(...

And On your backend, make sure that your webservice produces octet-stream and returning the file in base64 data format, i did this using Java JAX-RS like this:

@POST
@Path("/downloadfile")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadFile(...){
  String base64String = Base64.getEncoder().encodeToString(/*here you pass your file in byte[] format*/);
  return Response.ok(base64String).build();
}

1 Comment

Your answer resolved my issue of excel saying it was corrupt. I did try atob() but did not have Uint8array stuff. Thank you for sharing your knowledge.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.