Contexto: estoy tratando de descargar un archivo binario desde un backend (que requiere algunos datos publicados como json-body) y guardarlo con el protector de archivos usando el nombre de archivo especificado por el backend en el encabezado de disposición de contenido. Para acceder a los encabezados, creo que necesito HttpResponse.
Pero no puedo usar HttpClient.post<T>(...): Observable<HttpResponse<T>>; método con un Blob.
cuando llamo
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"'.Cuando pongo las opciones en un objeto propio como se ve en https://stackoverflow.com/a/48016652/2131459 (pero sin el "as"...) se llama el post(...):Observable y no puedo acceder a los encabezados.
Por cierto, incluso el ejemplo simple return this.http.get<Blob>('backendUrl', {responseType: 'blob'}); como se ve, por ejemplo, en https://stackoverflow.com/a/46882407/2131459 no funciona para mí.
Versiones utilizadas
Cuando use observe:response , no escriba la llamada ( post<Blob>(...) ), ya que el Observable devuelto será HttpResponse. Así que esto debería funcionar:
this.httpclient.post('MyBackendUrl', params, {observe: 'response', responseType: 'blob'} );¿Por qué sucede esto? Hay dos versiones del método de publicación, una con un tipo genérico y otra sin:
/** * 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>>;Otras respuestas son correctas pero les falta el ejemplo.
La respuesta principal primero cuando se establece el tipo de respuesta, el tipo de retorno de la respuesta se cambia a Blob. Para resolver esto, agregue observe: 'response' que devuelve HTTPResponse.
Ejemplo: me topé con este problema y pasé 6 horas resolviéndolo.
Entonces, aquí presento un ejemplo para obtener el nombre del archivo de los encabezados y descargar el archivo:
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; })); Aquí, http es una instancia de HttpClient, saveAs() es un método del paquete FileSaver npm igual que el OP.
Hay un problema más, es posible que obtenga solo 5 encabezados (Cache-Control, Pragma, etc.) en el resultado. encabezados y no su encabezado personalizado para, por ejemplo x-filename .
La razón detrás de este CORS. Básicamente, CORS no permite que los navegadores accedan a más de un puñado de encabezados (enumerados en el enlace anterior).
Entonces, resuelva esto, tendría que cambiar el servidor/API para enviar el encabezado Access-Control-Expose-Headers con la solicitud.
puedes usar como me gusta
responseType: 'blob' as 'json'