typescript - Angular (5) httpclient observe och responseType: 'blob'
Kontext: Jag försöker ladda ner en binär fil från ett backend (som kräver att viss data skickas som json-body) och spara den med file-saver med det filnamn som specificeras av backend i content-disposition-headern. För att få åtkomst till headern tror jag att jag behöver HttpResponse.
Men jag kan inte använda Angulars HttpClient.post<T>(...): Observable<HttpResponse<T>>;-metod med en Blob.
När jag ringer
this.httpclient.post<Blob>('MyBackendUrl',
params,
{observe: 'response', responseType: 'blob'});
the compiler complains about the 'blob' ('json' is accepted by the compiler):
error TS2345: Argument of type '{ observe: "response"; responseType: "blob"; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
Types of property 'observe' are incompatible.
Type '"response"' is not assignable to type '"body"'.
När jag lägger alternativen i ett eget objekt som ses i https://stackoverflow.com/a/48016652/2131459 (men utan "as" ...) anropas post(...):Observable och jag kan inte komma åt rubrikerna.
Förresten, även det enkla exemplet return this.http.get<Blob>('backendUrl', {responseType: 'blob'}); som ses t.ex. i https://stackoverflow.com/a/46882407/2131459 fungerar inte för mig.
Använda versioner
- Angular-version: 5.0.3 (kommer att uppdateras till senaste 5 om en vecka eller så)
- typescript: 2.4.2
- webpack: 3.8.1
Svar #1
När du använder observe:response, skriv inte anropet (post<Blob>(...)), eftersom den returnerade Observable kommer att vara av HttpResponse-typ. Så detta bör fungera:
this.httpclient.post('MyBackendUrl',
params,
{observe: 'response', responseType: 'blob'}
);
Varför detta händer är att det finns två versioner av postmetoden, en med en generisk typ, en utan:
/**
* Construct a POST request which interprets the body as JSON and returns the full event stream.
*
* @return an `Observable` of all `HttpEvent`s for the request, with a body type of `T`.
*/
post<T>(url: string, body: any | null, options: {
headers?: HttpHeaders | {
[header: string]: string | string[];
};
observe: 'events';
params?: HttpParams | {
[param: string]: string | string[];
};
reportProgress?: boolean;
responseType?: 'json';
withCredentials?: boolean;
}): Observable<HttpEvent<T>>;
/**
* Construct a POST request which interprets the body as an `ArrayBuffer` and returns the full response.
*
* @return an `Observable` of the `HttpResponse` for the request, with a body type of `ArrayBuffer`.
*/
post(url: string, body: any | null, options: {
headers?: HttpHeaders | {
[header: string]: string | string[];
};
observe: 'response';
params?: HttpParams | {
[param: string]: string | string[];
};
reportProgress?: boolean;
responseType: 'arraybuffer';
withCredentials?: boolean;
}): Observable<HttpResponse<ArrayBuffer>>;
Svar #2
du kan använda som
responseType: 'blob' as 'json'
Svar #3
Andra svar är rätt men de saknar exemplet.
Huvudsvar först när responseType är inställt ändras returtypen för svaret till Blob. För att lösa detta, lägg till observe: 'response' vilket returnerar HTTPResponse.
Exempel: Jag snubblade över detta problem och tillbringade 6 timmar med att lösa det.
Så, här presenterar jag ett exempel för att få filnamnet från headers och ladda ner filen:
downloadPDF(url: string): Observable<any> {
return this.http.get<any>(url, { responseType: 'blob', observe: 'response' }).pipe(
map((result:HttpResponse<Blob>) => {
console.log(result);
saveAs(result, "Quotation.pdf");
return result;
}));
Här är http en instans av HttpClient, saveAs() är en metod från FileSaver npm-paketet precis som hos OP.
Det finns ett problem till, du kan få endast 5 headers (Cache-Control, Pragma, etc) i result.headers och inte din anpassade header t.ex. x-filename.
Anledningen bakom detta CORS. I grunden tillåter inte CORS att webbläsare får åtkomst till mer än ett fåtal headers (listade i länken ovan).
Så för att lösa detta skulle du behöva ändra server/API för att skicka Access-Control-Expose-Headers-huvudet med förfrågan.
