0

I have following spring controller to download a file which is working fine when I directly call the endpoint and I get a csv file with encrypted content.

@GetMapping(value = "registered-cards")
    public ResponseEntity<byte[]> generateRegisteredCards(@RequestParam("from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime from,
                                                               @RequestParam("to") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime to) throws Exception {

        byte[] bytes = cfsbReportingService.generateRegisteredCardsReport(from, to);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Access-Control-Allow-Origin", "*");
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + "report-" +  LocalDateTime.now() + ".csv");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
    }

I have following code on my javascript to call the endpoint and download the file. The thing is I can download the file but I cannot decrypt it whereas when I download the file by directly calling the endpoint, it gets decrypted.

public getRegisteredCards(fromDate, toDate) : void {
        const fromEst = fromDate.startOf('day').tz('America/New_York').format();
        const endEst = toDate.endOf('day').tz('America/New_York').format();
        this.reportingService.generateNewRegisteredCardsFile(fromEst, endEst).then(
            (response:any) => {
                const blob = new Blob([response.data], {type:  'application/octet-stream'});
                const hiddenElement = document.createElement('a');
                hiddenElement.href = window.URL.createObjectURL(blob);
                hiddenElement.target = '_blank';
                hiddenElement.download = 'file.csv';
                hiddenElement.click();
            }
        ).catch(this.handleError(''));

Call to server:

public generateNewRegisteredCardsFile(from: String, to: String) {
        const url = `${this.api()}/reporting/v1/registered-cards?from=${from}&to=${to}` ;
        const headers = new Headers({'Content-Type': 'application/octet-stream', 'Accept': 'application/octet-stream', 'Access-Control-Allow-Origin': '*'});
        return this.$http.get(url, headers);
    }        }

What am I doing wrong here? I looked at tens of examples and that's how file gets downloaded.

Thank you!

Marko Previsic
  • 1,820
  • 16
  • 30
sansari
  • 558
  • 1
  • 7
  • 17
  • Obviously the response is not being parsed correctly. How is `this.reportingService` making the AJAX call? – Randy Casburn Jul 05 '19 at 18:55
  • @RandyCasburn Yes, I am using angular httpclient, just edited the question. – sansari Jul 05 '19 at 18:58
  • Angular's [HttpClient](https://angular.io/guide/http#type-checking-the-response) returns an Observable - yet you are using `.then()` as if it were a Promise. Are you sure you are not using the older Http class? (`from @angular.http;` instead of `from @angular.common.http;`) – Randy Casburn Jul 05 '19 at 19:07
  • I am not a lot familiar with angular, but I tested the same call with only string content and it worked with downloading correct content. So I am sure it is not returning a promise. – sansari Jul 05 '19 at 19:14
  • Of course. Can you at least look at the import statement and tell me which of my previous comment matches your import statement? – Randy Casburn Jul 05 '19 at 19:16
  • My service is `injecting` http and I cannot find import for the http. In package.json, `angular` version is `~1.5.11` if that helps. Otherwise please suggest me where to look. Thank you! – sansari Jul 05 '19 at 19:22
  • I created a data object to pass the byte array as a property field. Now parsing the object and creating the file; still decryption does not work. It seems kind of encoding problem?! – sansari Jul 05 '19 at 20:04

1 Answers1

0

I ended up adding a DTO object like below and changed my rest controller as follows:

@Data
public class RegisteredCardsReport {

    public RegisteredCardsReport(byte[] encryptedReport, String fileName) {
        this.encryptedReport = encryptedReport;
        this.fileName = fileName;
    }

    byte[] encryptedReport;
    String fileName;
}

//Rest Endpoint change

@GetMapping(value = "new-registered-cards")
    public ResponseEntity<RegisteredCardsReport> generateNewRegisteredCards(@RequestParam("from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime from,
                                                                                    @RequestParam("to") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime to) {

        byte[] encryptedRpt = ReportingService.generateRegisteredCardsReport(from, to);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Access-Control-Allow-Origin", "*");
        RegisteredCardsReport cardsReport = new RegisteredCardsReport(encryptedRpt, "registered-cards--" + LocalDateTime.now() + ".csv");
        return new ResponseEntity<>(cardsReport, headers, HttpStatus.OK);
    }

and finally used the accepted answer in this post to create file: Download File from Bytes in JavaScript

sansari
  • 558
  • 1
  • 7
  • 17