0

I am working to download a pdf file from User Interface (Angular), generated from Spring boot . I am able to download pdf file from browser with same API.

Quick help will be much appreciated.

In postman it gives response like this - Postman response

When trying from UI then getting below error- Error

SyntaxError: Unexpected token % in JSON at position 0 at JSON.parse () at XMLHttpRequest.onLoad message: "Unexpected token % in JSON at position 0" stack: "SyntaxError: Unexpected token % in JSON at position 0↵ at JSON.parse ()↵ at XMLHttpRequest.onLoad (http://localhost:4200/vendor.js:19662:51)↵

API Code

Controller code-

@RequestMapping(value = "/downloadPDF/", method = RequestMethod.GET, produces = "application/pdf")
    public ResponseEntity<Resource> downloadServicePack(@RequestHeader("Authorization") String token,
            HttpServletRequest request) throws WorkflowException, Exception {

        String fileName = "TWEVL_ServiceDesignPack.pdf";

        // String fileName ="ServiceDesignPdf.pdf";
        Resource resource = fileStorageService.loadFileAsResource(fileName);

        // Try to determine file's content type
        String contentType = null;
        try {
            contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
        } catch (IOException ex) {
            // logger.info("Could not determine file type.");
        }

        // Fallback to the default content type if type could not be determined
        if (contentType == null) {
            contentType = "application/octet-stream";
        }

        return ResponseEntity.ok().contentType(MediaType.parseMediaType(contentType))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);

    }

Service Code-

@Service
public class FileStorageService {

    private final Path fileStorageLocation;

    @Autowired
    public FileStorageService(FileStorageProperties fileStorageProperties) throws Exception {
        this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
                .toAbsolutePath().normalize();

        try {
            Files.createDirectories(this.fileStorageLocation);
        } catch (Exception ex) {
            throw new Exception("Could not create the directory where the uploaded files will be stored.", ex);
        }
    }

    
    public Resource loadFileAsResource(String fileName) throws Exception {
        try {
            Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
            Resource resource = new UrlResource(filePath.toUri());
            if(resource.exists()) {
                return resource;
            } else {
                throw new Exception("File not found " + fileName);
            }
        } catch (Exception ex) {
            throw new Exception("File not found " + fileName, ex);
        }
    }
}

Angular Code-

JWT Interceptor to pass token & other header-

 @Injectable()
    export class JwtInterceptor implements HttpInterceptor {
      constructor(private authenticationService: AuthenticationService) {}
    
      intercept(
        request: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
        // add authorization header with jwt token if available
        const token = this.authenticationService.currentUserValue;
            request = request.clone({
              setHeaders: {
                Authorization: `Bearer ${token.token}`,
                Accept: `application/pdf`,
                responseType:'blob',
                'Content-Type':`application/pdf`
              }
            });
        return next.handle(request);
      }
    }

API Call

  downloadServicePackPDF() {
    this.tcmtSrv
      .downloadServicePack()
      .subscribe(
        (blob: Blob)  => {
          console.log('report is downloaded');
       
        },
        (error) => {
          console.log(error);
         }
      );
  }

Service Code -

   downloadServicePack() {
   //header is being passed from interceptor
    return this.apiSrv.get(DOWNLOAD_SERVICE_PACK,'');
  }

Request Header- req header

Pinki Sharma
  • 121
  • 2
  • 16
  • 2
    Does this answer your question? [how to download a pdf file from an url in angular 5](https://stackoverflow.com/questions/50039015/how-to-download-a-pdf-file-from-an-url-in-angular-5) – R. Richards Apr 07 '21 at 17:22
  • @R.Richards i am already passing Accept & responseType in headers. It's giving same error. Just updated post with request header parameters – Pinki Sharma Apr 07 '21 at 17:30
  • I found using file saver package helpful for this. Check this post https://stackoverflow.com/questions/53246489/how-to-use-filesaver-in-angular-5-correctly – Tofique Sikder Apr 07 '21 at 17:34
  • 1
    The way you're doing `responseType` is incorrect. That is not a header. Look at the link I posted more closely. – R. Richards Apr 07 '21 at 17:40
  • Thanks @R.Richards, You were right. I was not passing responseType the way you suggested. I tried to pass it but it wasn't working. Later i checked that interceptor is overwriting these headers & other params given at service level. So i disabled interceptor & it worked but i can't disable/remove interceptor. Any idea on how to stop interceptor to run on a particular API? how to stop overwriting the headers passed at service layer by interceptor ? – Pinki Sharma Apr 08 '21 at 05:19
  • @PinkiSharma, does this answer help (how to bypass `AuthInterceptor`): https://stackoverflow.com/a/49013534/4192097 – MikeJ Apr 09 '21 at 04:26

1 Answers1

0

I was not passing responseType in the interceptor. I tried to pass it service ts but Interceptor was overriding these headers & other params given at service level.

Passed header like below in interceptor & it worked -

const newRequest = request.clone({ setHeaders: { Authorization: Bearer ${token.token}, "Content-Type": "text/plain", Accept: "text/plain" },responseType: "text", });
Pinki Sharma
  • 121
  • 2
  • 16