如何创建一个可下载链接,仅在 Angular 中单击时才从后端服务器加载文件

问题描述 投票:0回答:1

我有一个情况,我有一个项目列表,每个项目代表一个文件。所有这些文件都可以作为 blob 从后端获取。我希望在前端有链接,当用户点击时应该能够为他/她下载文件。
我预先下载的解决方案会创建一个

SafeResourceUrl

但是,我的问题是,因为我现在必须显示一个链接列表,最初下载所有链接是一种浪费。我需要做到这样,当我单击链接时,网络调用将去获取文件,然后应该打开下载弹出窗口。

这是我用于预下载的代码

组件

import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { AppService } from './app.service';
import { HttpResponse } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
  url?: SafeResourceUrl;
  stream: ArrayBuffer | null = null;
  fileName: string = 'test.pdf';

  constructor(
    private appService: AppService,
    private sanitizer: DomSanitizer
  ) {}

  ngOnInit(): void {
    this.appService.fetchPdf().subscribe((response: HttpResponse<Blob>) => {
      const blob = response.body!;
      blob.arrayBuffer().then((res) => {
        this.stream = res;
      });
      this.createLink(blob);
    });
  }

  async createLink(blob: Blob): Promise<void> {
    const buffer = await blob.arrayBuffer();
    if (buffer.byteLength) {
      const uint = new Uint8Array(buffer);
      let bin = '';
      for (let i = 0; i < uint.byteLength; i++) {
        bin += String.fromCharCode(uint[i]);
      }
      const base64 = window.btoa(bin);
      const url = `data:${blob.type};base64,${base64}`;
      this.url = this.sanitizer.bypassSecurityTrustResourceUrl(url);
    }
  }
}

服务

import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class AppService {
  private pdfUrl =
    'https://s28.q4cdn.com/392171258/files/doc_downloads/test.pdf';

  constructor(private http: HttpClient) {}

  fetchPdf(): Observable<HttpResponse<Blob>> {
    return this.http.get(this.pdfUrl, {
      observe: 'response',
      responseType: 'blob',
    });
  }
}

html

<h1>download test</h1>
<div *ngIf="url">
  <a [href]="url" [download]="fileName">{{ fileName }}</a>
</div>

这里是演示

javascript html angular typescript blob
1个回答
0
投票

对于这种情况,最方便的做法是从后端为您提供要使用的文件 ID 列表,当用户单击下载按钮时,将调用后端以提供文件的链接元素并生成文件。 我在下面留下了一个例子

服务

const backendURL = "YOUR_BACKEND_URL"
   
getListFromBackend() {
  let uri = `${backendURL}/getArchiveList`;
  return this.http.get(uri);
}

fetchPdf(): Observable<HttpResponse<Blob>> {
    let uri = `${backendURL}/archives/${id}`;
    return this.http.get(`${uri}`, {
      observe: 'response',
      responseType: 'blob',
    });
}

组件

itemsList = [];

ngOnInit(): void {
  this.appService.getListFromBackend().subscribe((response) => {
    this.itemsList = response; // [id: 1, id: 2, id: 3]
  });
}

callItemBackend(id) {
  this.appService.fetchPdf(id).subscribe((response: HttpResponse<Blob>) => {
    const blob = response.body!;
      blob.arrayBuffer().then((res) => {
        this.stream = res;
      });
      this.createLink(blob);
  });
}

async createLink(blob: Blob): Promise<void> {
    const buffer = await blob.arrayBuffer();
    if (buffer.byteLength) {
      const uint = new Uint8Array(buffer);
      let bin = '';
      for (let i = 0; i < uint.byteLength; i++) {
        bin += String.fromCharCode(uint[i]);
      }
      const base64 = window.btoa(bin);
      const url = `data:${blob.type};base64,${base64}`;
      this.url = this.sanitizer.bypassSecurityTrustResourceUrl(url);
      const link = document.createElement('a');
      if(link) {
        link.setAttribute('target', '_blank');
        link.setAttribute('href', this.url);
        link.setAttribute('download', `NAME.pdf`);
        document.body.appendChild(link);
        link.click();
        link.remove();
      }
    }
}

html

<div *ngFor="let item of this.itemsList">
  <a (click)="this.callItemBackend(item.id)">DOWNLOAD</a>
</div>
© www.soinside.com 2019 - 2024. All rights reserved.