TypeError: res.blob is not a function

16,378

Use the res.body instead of res while constructing the Blob.

downloadPDF(): any {
    return this.http.get(environment.api.urls.downloads.getPdf, {
        responseType: 'blob'
      })
      .pipe(
        map((res: any) => {
          return new Blob([res.body], {
            type: 'application/pdf'
          })
        })
      );
    } 
Share:
16,378
Peter Penzov
Author by

Peter Penzov

Updated on July 17, 2022

Comments

  • Peter Penzov
    Peter Penzov almost 2 years

    I want to implement file download using this Angular 6 code:

    Rest API:

    private static final Logger LOG = LoggerFactory.getLogger(DownloadsController.class);
    
    @GetMapping(path="export") 
    public ResponseEntity<byte[]> export() throws IOException {
        File pdfFile = Paths.get(EXTERNAL_FILE_PATH).toFile();
    
    
        byte[] fileContent = Files.readAllBytes(pdfFile.toPath());
    
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/pdf"));
        // Here you have to set the actual filename of your pdf
        String filename = "output.pdf";
        headers.setContentDispositionFormData(filename, filename);
        headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        ResponseEntity<byte[]> response = new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
        return response;
    }
    

    Service:

    import {Injectable} from '@angular/core';
    import {HttpClient, HttpParams} from "@angular/common/http";
    import {Observable} from "rxjs/index";
    import {environment} from "../../../environments/environment";
    import {HttpUtils} from "../common/http-utils";
    import { map } from 'rxjs/operators';
    import {Http, ResponseContentType} from '@angular/http';
    
    
    @Injectable({
      providedIn: 'root'
    })
    export class DownloadService {
    
      constructor(private http: HttpClient) {
      }
    
      downloadPDF(): any {
        return this.http.get(environment.api.urls.downloads.getPdf, {
            responseType: 'blob'
          })
          .pipe(
            map((res: any) => {
              return new Blob([res.blob()], {
                type: 'application/pdf'
              })
            })
          );
        }  
    }
    

    Component:

    import {Component, OnInit} from '@angular/core';
    import {DownloadService} from "../service/download.service";
    import {ActivatedRoute, Router} from "@angular/router";
    import {flatMap} from "rxjs/internal/operators";
    import {of} from "rxjs/index";
    import { map } from 'rxjs/operators';
    
    @Component({
      selector: 'app-download',
      templateUrl: './download.component.html',
      styleUrls: ['./download.component.scss']
    })
    export class DownloadComponent implements OnInit {
    
      constructor(private downloadService: DownloadService,
                  private router: Router,
                  private route: ActivatedRoute) {
      }
    
      ngOnInit() {   
      }
    
      export() {               
        this.downloadService.downloadPDF().subscribe(res => {
          const fileURL = URL.createObjectURL(res);
          window.open(fileURL, '_blank');
        });         
      } 
    }
    

    The file is present in the directory but when I try to download it I get error:

    ERROR TypeError: res.blob is not a function
        at MapSubscriber.project (download.service.ts:24)
        at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:35)
        at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
        at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:41)
        at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
        at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next (filter.js:38)
        at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
        at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:84)
        at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:15)
        at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
    

    Do you know how I can fix this issue? Do I need to add additional configuration in order to download the file via Angular web UI?

    I use spring-boot-starter-parent version 2.1.0.RELEASE and angular 6

    Update: I tested this but nothing happens:

    downloadPDF(): any {
        return this.http.get(environment.api.urls.downloads.getPdf, {
            responseType: 'blob'
          })
          .pipe(
            map((res: any) => {
              return new Blob([res], {
                type: 'application/pdf'
              })
            })
          );
        } 
    
  • Peter Penzov
    Peter Penzov over 5 years
    It's correct. I suppose that something is missing into the typescript code?
  • Peter Penzov
    Peter Penzov over 5 years
    Any other ideas?
  • Sunil Singh
    Sunil Singh over 5 years
    try once with res._body instead of res.body