Encountering an issue when trying to download a PDF from an Angular 6 frontend using a Spring Boot API - receiving an error related to

When I directly call the Spring Boot API in the browser, it successfully creates and downloads a PDF report. However, when I try to make the same GET request from Angular 6, I encounter the following error:

Here is the code snippet for the Spring Boot (Java) API:

@RequestMapping(value = "/app_report/en", method = RequestMethod.GET)
@ResponseBody
public void getEnRpt(HttpServletResponse response, @RequestParam("appNum") String appNum) throws JRException, IOException, SQLException {

    JasperReport jasperReport = JasperCompileManager.compileReport("./src/main/resources/jasperReports/App_created_en.jrxml");

    Connection connection = dataSource.getConnection();

    Map<String, Object> params = new HashMap<>();
    params.put("P_APP_NO", appNum);
    JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, connection);

    response.setContentType("application/x-pdf");
    response.setHeader("Content-disposition", "inline; filename=App_report_en.pdf");

    final OutputStream outStream = response.getOutputStream();
    JasperExportManager.exportReportToPdfStream(jasperPrint, outStream);
}

Below are two versions of the Angular code attempting to call the API:

this.http.get(this.api_url + reportUrl, {
  responseType: 'blob'
}, ).subscribe((response: File) => {
  console.log('report is downloaded');
});

this.http.get(this.api_url + reportUrl).subscribe(
  (response) => {
    console.log('report is downloaded');
  });

This is the console error that appears after making the API calls from Angular:

error:
SyntaxError: Unexpected token % in JSON at position 0 at JSON.parse (<anonymous>) at XMLHttpRequest.onLoad 
message: "Http failure during parsing for https://localhost:7001/reports/app_report/en?appNum=xxxxxxx"
​
name: "HttpErrorResponse"
​
ok: false
​
status: 200
​
statusText: "OK"
​
url: "https://localhost:7001/reports/app_report/en?appNum=xxxxxx"

The goal is to replicate the direct download behavior seen in the browser when calling the API from Angular.

The response headers provided by the API are:

Content-disposition 
inline; filename=App_report_en.pdf
Content-Type    
application/x-pdf

Why does Angular not download the file as expected, even though the request is successful?

Answer №1

To solve the issue with JSON parsing, it is important to inform the http client that the response will be in blob format by including responseType: 'blob' in the request options.

Next, to enable the browser to open the file, you can refer to the steps outlined in this blog post


    const fileName = "report.pdf";
    this.http.get(this.api_url + reportUrl, {  responseType: 'blob'})
    .subscribe((blob: Blob) => {
    console.log('report has been downloaded');
    
    if (navigator.msSaveBlob) 
    { 
        // For IE 10+
        navigator.msSaveBlob(blob, filename);
    }
    else 
    {
        let link = document.createElement("a");
        if (link.download !== undefined) 
        {
            let url = URL.createObjectURL(blob);
            link.setAttribute("href", url);
            link.setAttribute("download", fileName);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            }
            else
            {
                //html5 download not supported
            }
        }   
});

This method should function correctly on Internet Explorer 10 and newer versions of browsers, with the exception of iOS devices (refer to CanIuse)

Answer №2

Integrating Spring Boot, Jaspersoft, and Angular

In the component.ts file

generateReport() {
this.reportService.generateReport(this.form.value).subscribe(response => {
  let url = window.URL.createObjectURL(response.data);
  let a = document.createElement('a');
  document.body.appendChild(a);
  a.setAttribute('style', 'display: none');
  a.setAttribute('target', '_blank');
  a.href = url;
  a.download = response.filename;
  a.click();
  window.URL.revokeObjectURL(url);
  a.remove();
}, error => {
  console.log(error);
});

}

In the service.ts file

   public generateReport(data: Data) {
   
    return this.httpService.getReport(url, data)
      .pipe(map((response) => {
        return {
          filename: 'report.pdf',
          data: new Blob([response], { type: 'application/pdf' })
        };
      }));
  }

Calling the REST API

    getReport(url: any, data: any): Observable<any> {
        const headers = new HttpHeaders({
            'Authorization': 'Bearer ' + this.tokenStoreService.getToken()
        })
        return this.http.post(this.URL + url, data, { headers, responseType: 'arraybuffer' as 'json'});
 }

Setting up Jasper Report in Spring Boot

public JasperReport getJasperReport(String reportJrxml) throws Exception {
     Resource resource = new ClassPathResource(reportJrxml);
     InputStream inputStream = resource.getInputStream();
     JasperDesign jasperDesign = JRXmlLoader.load(inputStream);

    return JasperCompileManager.compileReport(jasperDesign);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to consolidate React and React-DOM into a unified library instead of having them separate?

Is it possible to combine React.JS and React-DOM.JS into a single library? In all the web applications I've encountered, we always have to import both libraries separately. Have there been any cases where either of these libraries can be used on its ...

Searching recursively for keys with empty values in an array using Javascript

I've written a function that recursively locates empty values in a nested array. The function initially produces the correct value, but it seems to reset it to the input value before returning the result. What could I be overlooking? Below is my co ...

The combination of React.js and debouncing on the onChange event seems to be malfunctioning

I recently incorporated a React component that triggers an event on change. Here's how I did it: NewItem = React.createClass({ componentWillMount: function() { this._searchBoxHandler = debounce(this._searchBoxHandler, 500); }, _searchBoxH ...

How can you generate a distinct id value for each element within an ngFor iteration in Angular 4?

I encountered an issue where I must assign a distinct id value to each data row within my *ngFor loop in angular 4. Here is the code snippet: <div *ngFor="let row of myDataList"> <div id="thisNeedsToBeUnique">{{ row.myValue }}</div> & ...

a common pattern used to substitute website links

I am trying to modify my code that creates HTML links from plain text. While it currently works well, I want to exclude any links that contain .png or .jpg extensions. Does anyone have suggestions on how to adjust the regular expression? var urlPattern ...

The issue of Bootstrap dynamic tabs retaining their active state even after switching tabs, leading to elements being stacked

For my university project, I am developing a website that resembles a text editor using Bootstrap as the framework. To create the website menus, dynamic tabs have been utilized. The following is the code snippet I have implemented: <!--Bootstrap ...

SSI stands for Server Side Includes, a feature that allows

I have multiple versions of the same HTML page, each with only one hidden variable that is different. This variable is crucial for tracking purposes. Now, I am exploring options to rewrite this by incorporating a HTML file with a hidden variable. Here is ...

Issue with React.js code not being detected in TSX file (Visual Studio 2015 Update 1 RC)

Currently, I am utilizing Visual Studio 2015 with update 1 release candidate. Interestingly, I have managed to successfully incorporate React.js code and syntax highlighting within a .JSX file. However, when it comes to a .TSX file, nothing seems to be wor ...

Express (generator) is failing to load custom scripts located in the public folder

I'm new to node and express and I'm facing a problem. I want to load a custom script.js from the public folder, but it's not loading. There are no errors in the console or anything in the network tab. When I try to access the URL localhost:3 ...

Leverage the camera functionality in both native and web applications using Ionic/AngularJS and Cordova

Could you provide some guidance on how to use the Camera feature in both web and native environments? I have tried implementing it using the code snippet below, taken from ng-cordova documentation: $scope.takePicture = function() { var options ...

Switching the Require statement to an Import statement led to an error popping up

Currently, I am exploring the use of Ajv with typescript. import { Ajv } from "ajv"; let ajv = new Ajv({allErrors: true}); I have encountered an error and I'm unsure why it is occurring: [ts] 'Ajv' only refers to a type, but is being u ...

How can I implement user account functionality with only JavaScript in an Angular frontend and Node.js/Express server?

Many resources I've come across utilize php or a similar language. With an Angular frontend and Node/express server code in place, but no backend yet, I'm uncertain about how to approach user sign-up. ...

Omit an enum item from selection when referencing the key within the Enum

Within my enum, I have defined multiple keys: export enum MyTypeEnum { one = 'one', two = 'two', three = 'three', four = 'four' } To ensure certain types must contain these keys, I use the following ...

React- Error: Unhandled Type Mismatch in function call for _this4.getNotes

As I delve into learning React, I've created a basic application to manage notes with titles and descriptions. This application interacts with a REST API built using Go, enabling me to perform operations like retrieving, editing, creating, and deleti ...

Tips for dynamically updating the path in angular as you scroll

https://i.stack.imgur.com/KlmnQ.jpg Currently utilizing Angular 17, my goal is to create a page with multiple components accessible through unique paths. Clicking on the navigation menu should automatically scroll to the desired component and update the p ...

Format Currency Fields with Comma Separated Values in Angular and Material UI

In our Angular 9 project, we are implementing currency input fields that require a standard masked label displaying a comma separated format. When the user enters 56000.55 into the input field, upon blur event, we need to show 56,000.55 as a comma separat ...

What are the steps for implementing responsive design animation in my particular scenario?

Can someone please help me with a strange bug in Chrome? I am trying to create a responsive design for my app. The width of the 'item' element should change based on the browser's width. It works fine when the page first loads in Chrome, b ...

Tips on effectively storing extra object properties across all entries in a MongoDB document group

Currently, I have a node module that involves parsing a .csv file into MongoDB documents. The issue I am encountering is that only the first inserted document contains certain metadata fields, while the rest do not retain these fields. I am seeking guidan ...

Angular is experiencing difficulty locating the routing path for the auxiliary `router-outlet`

Exploring the intricacies of routing in Angular to gain a deeper understanding of the concept. Encountering an issue where I am receiving an exception NG04002: Cannot match any routes. URL Segment: 'about' when attempting to click on the About li ...

Having trouble updating npm using npm install npm@latest -g and encountering an error?

Encountering errors and warnings while updating npm to the latest version c:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\Web Tools\External>npm cache clean --force npm WARN usin ...