Angular 6从rest api下载文件

gme*_*exo 29 rest typescript angular6

我有我的REST API,我把我的pdf文件,现在我希望我的角度应用程序通过我的网络浏览器点击下载,但我得到了HttpErrorResponse

"位于0的JSON中出现意外的标记%"

"SyntaxError:JSON.parse中位置0↵的JSON中出现意外的标记%(

这是我的终点

    @GetMapping("/help/pdf2")
public ResponseEntity<InputStreamResource> getPdf2(){

    Resource resource = new ClassPathResource("/pdf-sample.pdf");
    long r = 0;
    InputStream is=null;

    try {
        is = resource.getInputStream();
        r = resource.contentLength();
    } catch (IOException e) {
        e.printStackTrace();
    }

        return ResponseEntity.ok().contentLength(r)
                .contentType(MediaType.parseMediaType("application/pdf"))
                .body(new InputStreamResource(is));

}
Run Code Online (Sandbox Code Playgroud)

这是我的服务

  getPdf() {

this.authKey = localStorage.getItem('jwt_token');

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type':  'application/pdf',
    'Authorization' : this.authKey,
    responseType : 'blob',
    Accept : 'application/pdf',
    observe : 'response'
  })
};
return this.http
  .get("http://localhost:9989/api/download/help/pdf2", httpOptions);
Run Code Online (Sandbox Code Playgroud)

}

和调用

this.downloadService.getPdf()
  .subscribe((resultBlob: Blob) => {
  var downloadURL = URL.createObjectURL(resultBlob);
  window.open(downloadURL);});
Run Code Online (Sandbox Code Playgroud)

Pie*_*ier 42

我用这种方式解决了这个问题(请注意我已经合并了堆栈溢出时找到的多个解决方案,但我找不到引用.请随意在评论中添加它们).

在我的服务中,我有:

public getPDF(): Observable<Blob> {   
//const options = { responseType: 'blob' }; there is no use of this
    let uri = '/my/uri';
    // this.http refers to HttpClient. Note here that you cannot use the generic get<Blob> as it does not compile: instead you "choose" the appropriate API in this way.
    return this.http.get(uri, { responseType: 'blob' });
}
Run Code Online (Sandbox Code Playgroud)

在组件中,我有(这是从多个答案合并的部分):

public showPDF(): void {
    this.myService.getPDF()
        .subscribe(x => {
            // It is necessary to create a new blob object with mime-type explicitly set
            // otherwise only Chrome works like it should
            var newBlob = new Blob([x], { type: "application/pdf" });

            // IE doesn't allow using a blob object directly as link href
            // instead it is necessary to use msSaveOrOpenBlob
            if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                window.navigator.msSaveOrOpenBlob(newBlob);
                return;
            }

            // For other browsers: 
            // Create a link pointing to the ObjectURL containing the blob.
            const data = window.URL.createObjectURL(newBlob);

            var link = document.createElement('a');
            link.href = data;
            link.download = "Je kar.pdf";
            // this is necessary as link.click() does not work on the latest firefox
            link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));

            setTimeout(function () {
                // For Firefox it is necessary to delay revoking the ObjectURL
                window.URL.revokeObjectURL(data);
                link.remove();
            }, 100);
        });
}
Run Code Online (Sandbox Code Playgroud)

上面的代码适用于IE,Edge,Chrome和Firefox.但是,我并不喜欢它,因为我的组件被浏览器特定的东西所污染,这肯定会随着时间而改变.

  • 这个答案仍然适用于 Chrome:78.0.3904.97 和 Firefox:70.0.1。但是,我找不到可靠的方法来解决这个问题。你会如何解决它? (2认同)

gme*_*exo 22

我解决如下:

// header.component.ts
this.downloadService.getPdf().subscribe((data) => {

  this.blob = new Blob([data], {type: 'application/pdf'});

  var downloadURL = window.URL.createObjectURL(data);
  var link = document.createElement('a');
  link.href = downloadURL;
  link.download = "help.pdf";
  link.click();

});



//download.service.ts
getPdf() {

  this.authKey = localStorage.getItem('jwt_token');

  const httpOptions = {
    responseType: 'blob' as 'json',
    headers: new HttpHeaders({
      'Authorization': this.authKey,
    })
  };

  return this.http.get(`${this.BASE_URL}/help/pdf`, httpOptions);
}
Run Code Online (Sandbox Code Playgroud)

  • window.URL.createObjectURL 已弃用。这是错误的。 (3认同)
  • 我不愿发表简单的谢谢您的评论,因为它们通常没有增值作用……但是我必须为此发表评论。今天,我一直在为WAY苦苦寻找。我一直在寻找从`this.blob`到`link.click()`的代码,您只是救了我我一整夜的东西!谢谢!!!!!! (2认同)
  • 您应该将 this.blob 传递给 createObjectURL,而不是数据。var downloadURL = window.URL.createObjectURL(this.blob); (2认同)
  • 使用 URL.createObjectURL,而不是 window.URL.createObjectURL,显然较新的浏览器认为 window.URL.createObjectURL 存在安全风险 (2认同)

小智 10

对于 Angular 12+,我想出了这样的东西:

this.ApiService
    .getFileFromApi()
    .pipe(take(1))
    .subscribe((response) => {
        const downloadLink = document.createElement('a');
        downloadLink.href = URL.createObjectURL(new Blob([response.body], { type: response.body.type }));

        const contentDisposition = response.headers.get('content-disposition');
        const fileName = contentDisposition.split(';')[1].split('filename')[1].split('=')[1].trim();
        downloadLink.download = fileName;
        downloadLink.click();
    });
Run Code Online (Sandbox Code Playgroud)

订阅是get()通过 Angular HttpClient 进行的。

// api-service.ts

getFileFromApi(url: string): Observable<HttpResponse<Blob>> {
  return this.httpClient.get<Blob>(this.baseApiUrl + url, { observe: 'response', responseType: 'blob' as 'json'});
}
Run Code Online (Sandbox Code Playgroud)