Angular: How to download a file from HttpClient?

后端 未结 6 1595
挽巷
挽巷 2020-12-04 23:57

I need download an excel from my backend, its returned a file.

When I do the request I get the error:

TypeError: You provided \'undefined\' wh

相关标签:
6条回答
  • 2020-12-04 23:58

    I ended up here when searching for ”rxjs download file using post”.

    This was my final product. It uses the file name and type given in the server response.

    import { ajax, AjaxResponse } from 'rxjs/ajax';
    import { map } from 'rxjs/operators';
    
    downloadPost(url: string, data: any) {
        return ajax({
            url: url,
            method: 'POST',
            responseType: 'blob',
            body: data,
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'text/plain, */*',
                'Cache-Control': 'no-cache',
            }
        }).pipe(
            map(handleDownloadSuccess),
        );
    }
    
    
    handleDownloadSuccess(response: AjaxResponse) {
        const downloadLink = document.createElement('a');
        downloadLink.href = window.URL.createObjectURL(response.response);
    
        const disposition = response.xhr.getResponseHeader('Content-Disposition');
        if (disposition) {
            const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
            const matches = filenameRegex.exec(disposition);
            if (matches != null && matches[1]) {
                const filename = matches[1].replace(/['"]/g, '');
                downloadLink.setAttribute('download', filename);
            }
        }
    
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
    }
    
    0 讨论(0)
  • 2020-12-05 00:06

    After spending much time searching for a response to this answer: how to download a simple image from my API restful server written in Node.js into an Angular component app, I finally found a beautiful answer in this web Angular HttpClient Blob. Essentially it consist on:

    API Node.js restful:

       /* After routing the path you want ..*/
      public getImage( req: Request, res: Response) {
    
        // Check if file exist...
        if (!req.params.file) {
          return res.status(httpStatus.badRequest).json({
            ok: false,
            msg: 'File param not found.'
          })
        }
        const absfile = path.join(STORE_ROOT_DIR,IMAGES_DIR, req.params.file);
    
        if (!fs.existsSync(absfile)) {
          return res.status(httpStatus.badRequest).json({
            ok: false,
            msg: 'File name not found on server.'
          })
        }
        res.sendFile(path.resolve(absfile));
      }
    

    Angular 6 tested component service (EmployeeService on my case):

      downloadPhoto( name: string) : Observable<Blob> {
        const url = environment.api_url + '/storer/employee/image/' + name;
    
        return this.http.get(url, { responseType: 'blob' })
          .pipe(
            takeWhile( () => this.alive),
            filter ( image => !!image));
      }
    

    Template

     <img [src]="" class="custom-photo" #photo>
    

    Component subscriber and use:

    @ViewChild('photo') image: ElementRef;
    
    public LoadPhoto( name: string) {
        this._employeeService.downloadPhoto(name)
              .subscribe( image => {
                const url= window.URL.createObjectURL(image);
                this.image.nativeElement.src= url;
              }, error => {
                console.log('error downloading: ', error);
              })    
    }
    
    0 讨论(0)
  • 2020-12-05 00:09

    Try something like this:

    type: application/ms-excel

    /**
     *  used to get file from server
     */
    
    this.http.get(`${environment.apiUrl}`,{
              responseType: 'arraybuffer',headers:headers} 
             ).subscribe(response => this.downLoadFile(response, "application/ms-excel"));
    
    
        /**
         * Method is use to download file.
         * @param data - Array Buffer data
         * @param type - type of the document.
         */
        downLoadFile(data: any, type: string) {
            let blob = new Blob([data], { type: type});
            let url = window.URL.createObjectURL(blob);
            let pwa = window.open(url);
            if (!pwa || pwa.closed || typeof pwa.closed == 'undefined') {
                alert( 'Please disable your Pop-up blocker and try again.');
            }
        }
    
    0 讨论(0)
  • 2020-12-05 00:10

    It took me a while to implement the other responses, as I'm using Angular 8 (tested up to 10). I ended up with the following code (heavily inspired by Hasan).

    Note that for the name to be set, the header Access-Control-Expose-Headers MUST include Content-Disposition. To set this in django RF:

    http_response = HttpResponse(package, content_type='application/javascript')
    http_response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
    http_response['Access-Control-Expose-Headers'] = "Content-Disposition"
    

    In angular:

      // component.ts
      // getFileName not necessary, you can just set this as a string if you wish
      getFileName(response: HttpResponse<Blob>) {
        let filename: string;
        try {
          const contentDisposition: string = response.headers.get('content-disposition');
          const r = /(?:filename=")(.+)(?:")/
          filename = r.exec(contentDisposition)[1];
        }
        catch (e) {
          filename = 'myfile.txt'
        }
        return filename
      }
    
      
      downloadFile() {
        this._fileService.downloadFile(this.file.uuid)
          .subscribe(
            (response: HttpResponse<Blob>) => {
              let filename: string = this.getFileName(response)
              let binaryData = [];
              binaryData.push(response.body);
              let downloadLink = document.createElement('a');
              downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: 'blob' }));
              downloadLink.setAttribute('download', filename);
              document.body.appendChild(downloadLink);
              downloadLink.click();
            }
          )
      }
    
      // service.ts
      downloadFile(uuid: string) {
        return this._http.get<Blob>(`${environment.apiUrl}/api/v1/file/${uuid}/package/`, { observe: 'response', responseType: 'blob' as 'json' })
      }
    
    
    0 讨论(0)
  • 2020-12-05 00:24

    Blobs are returned with file type from backend. The following function will accept any file type and popup download window:

    downloadFile(route: string, filename: string = null): void{
    
        const baseUrl = 'http://myserver/index.php/api';
        const token = 'my JWT';
        const headers = new HttpHeaders().set('authorization','Bearer '+token);
        this.http.get(baseUrl + route,{headers, responseType: 'blob' as 'json'}).subscribe(
            (response: any) =>{
                let dataType = response.type;
                let binaryData = [];
                binaryData.push(response);
                let downloadLink = document.createElement('a');
                downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, {type: dataType}));
                if (filename)
                    downloadLink.setAttribute('download', filename);
                document.body.appendChild(downloadLink);
                downloadLink.click();
            }
        )
    }
    
    0 讨论(0)
  • 2020-12-05 00:24

    Using Blob as a source for an img:

    template:

    <img [src]="url">
    

    component:

     public url : SafeResourceUrl;
    
     constructor(private http: HttpClient, private sanitizer: DomSanitizer) {
       this.getImage('/api/image.jpg').subscribe(x => this.url = x)
     }
    
     public getImage(url: string): Observable<SafeResourceUrl> {
       return this.http
         .get(url, { responseType: 'blob' })
         .pipe(
           map(x => {
             const urlToBlob = window.URL.createObjectURL(x) // get a URL for the blob
             return this.sanitizer.bypassSecurityTrustResourceUrl(urlToBlob); // tell Anuglar to trust this value
           }),
         );
     }
    

    Further reference about trusting save values

    0 讨论(0)
提交回复
热议问题