Hur man laddar ner en Excel-fil i Angular 8 som ett API-svar


Jag har en API som returnerar ett Excel-dokument som svar. Förfrågan kommer att vara ett enkelt JSON.

Jag har sökt på Google och hittat någon kodbas för att ladda ner filen och jag har använt den i min applikation, men jag får några fel och kan inte hitta lösningen. Nedan är min kodbas:

component.ts

import rxjs/Rx;

details = {id: 75,name: "some name"}

this.nameService.getData(this.details).subscribe(response => {
this.downloadFile(response);
})

downloadFile(data: Response) {
  const blob = new Blob([data], { type: '.xlsx' });
  const url= window.URL.createObjectURL(blob);
  window.open(url);
}

nameService.ts

getData(postData) {
  return this.httpService.post('https://localhost:8080/getFile/', postData);
}

httpService.ts

constructor(private http: HttpClient)
post(apiEndpoint: string, request: any) :Observable<any> {
 return this.http.post<any>(apiEndpoint,request);
}

Med ovanstående kodbas får jag nedanstående två fel och filen laddas inte ner.

  1. Får felet:

"Typen Response kan inte tilldelas typen Blobpart" vid skapande av Blob (const blob=new Blob([data], { type: '.xlsx' });)

  1. Om jag ändrar datan till vilken (downloadFile(data: any)) som helst försvinner ovanstående fel(1) men jag får ett httperror-svar som 'Syntaxfel: oväntad token P i JSON på position 0 vid json.parse'

Var vänlig hjälp om någon hittar någon lösning på ovanstående problem.

Svar #1

  1. Du behöver ange svarshuvudet { responseType: 'blob'} i förfrågan.

  2. Du behöver ange rätt MIME-typ när du skapar blob-filen. (t.ex. application/octet-stream eller application/vnd.openxmlformats-officedocument.spreadsheetml.sheet).

komponent.ts

downloadFile(data: Response) {
  const blob = new Blob([data], { type: 'application/octet-stream' });
  const url= window.URL.createObjectURL(blob);
  window.open(url);
}

Svar #2

Lägg till header { responseType: 'blob'}

Så här:

this.http.post<any>(apiEndpoint,request,{ responseType: 'blob'} )

Svar #3

Även om användning av { responseType: 'blob'} som de flesta svar här säger fungerar, skulle jag föreslå att använda responseType: 'arraybuffer' istället för blob med observe: 'response'. Ditt anrop skulle då se ut så här:

this.httpClient.get(resource, {
  headers: this.httpHeaders, // Any custom client side headers like Authorization
  observe: 'response',
  responseType: 'arraybuffer'
});

Fördelen med detta är tvåfaldig:

  1. Arraybuffer är ett generiskt flöde av bytes och Blob-objektet kan skapas med antingen en blob eller en arraybuffer, med hjälp av Content-Type
  2. observe: 'response' kommer också att inkludera svarshuvuden som du har ställt in på servern i det analyserade svaret.

Jag använder denna metod för att lägga filnamnet och MIME-typen för arraybuffer i Content-Disposition och Content-Type svarshuvuden och sedan använda en generell nedladdningstjänst på klientsidan.

Jag skulle också föreslå att använda ett File-objekt istället för bara Blob, vilket ger dig flexibiliteten att ge det ett filnamn på följande sätt:

public downloadFile(response: any, fileName?: string) {
    const blob = new Blob([response.body], { type: response.headers.get('content-type') });
    fileName = fileName || response.headers.get('content-disposition').split(';')[0];
    const file = new File([blob], fileName, { type: response.headers.get('content-type') });
    saveAs(file);
}

Detta kommer också att lösa problemet som @knbibin tog upp om att använda ett eget filnamn.

Relaterade artiklar