angular - Hur man hanterar fel för svarstyp blob i HttpRequest


Jag gör ett HTTP-anrop med httpClient och använder responstypen som 'blob', men problemet är att när det går in i felblocket förblir responstypen 'blob'. Detta orsakar problem med min felhantering.

this.httpClient.get('http://m502126:3000/reports/perdate', {
observe: 'body',
responseType: 'blob',
params: new HttpParams().set('START_DATE', startDate)
 .set('END_DATE', endDate)
 .set('MIXER', mixer)
 .set('ATTACH', 'true')

 }).subscribe(data => {
 console.log(data);
},
error => {
 console.log(error);

}

)

problemet är att jag sätter begärans typ som 'blob' och typ av fel är vad som helst. Så när felet kommer och går i felblocket förblir svarstypen 'blob'. Hur hanterar man detta?

Svar #1

Jag ställdes inför samma problem. För att hantera felrespons från en blob-begäran måste du analysera ditt felinnehåll via FileReader

Detta är ett känt Angular-problem och ytterligare detaljer kan läsas där. Du kan även hitta olika lösningar på ditt problem där.

Till exempel kan du använda denna funktion för att parsa ditt fel i JSON:

  parseErrorBlob(err: HttpErrorResponse): Observable<any> {
    const reader: FileReader = new FileReader();

    const obs = Observable.create((observer: any) => {
      reader.onloadend = (e) => {
        observer.error(JSON.parse(reader.result));
        observer.complete();
      }
    });
    reader.readAsText(err.error);
    return obs;
}

och använd det så här:

public fetchBlob(): Observable<Blob> {
  return this.http.get(
    'my/url/to/ressource',
    {responseType: 'blob'}
  ).pipe(catchError(this.parseErrorBlob))
}  

Svar #2

Det kan också göras med: error.text()

this.dataService
  .getFile()
  .subscribe((response) => {
    FileSaver.saveAs(response.body, 'file.txt');
  }, async (error) => {
    const message = JSON.parse(await error.error.text()).message;

    this.toast.error(message, 'Error');
  });

Svar #3

Svaret från SplitterAlex nämner Angular-problemet men nämner inte en mycket bra lösning som ges där av JaapMosselman som innebär att skapa en HttpInterceptor som kommer att översätta Blob tillbaka till JSON.

På det här sättet behöver du inte implementera detta genom hela din applikation, och när problemet är åtgärdat kan du helt enkelt ta bort det.

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable()
export class BlobErrorHttpInterceptor implements HttpInterceptor {
    public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(req).pipe(
            catchError(err => {
                if (err instanceof HttpErrorResponse && err.error instanceof Blob && err.error.type === "application/json") {
                    // https://github.com/angular/angular/issues/19888
                    // When request of type Blob, the error is also in Blob instead of object of the json data
                    return new Promise<any>((resolve, reject) => {
                        let reader = new FileReader();
                        reader.onload = (e: Event) => {
                            try {
                                const errmsg = JSON.parse((<any>e.target).result);
                                reject(new HttpErrorResponse({
                                    error: errmsg,
                                    headers: err.headers,
                                    status: err.status,
                                    statusText: err.statusText,
                                    url: err.url || undefined
                                }));
                            } catch (e) {
                                reject(err);
                            }
                        };
                        reader.onerror = (e) => {
                            reject(err);
                        };
                        reader.readAsText(err.error);
                    });
                }
                throw err;
            })
        );
    }
}

Deklarera det i din AppModule eller CoreModule:

import { HTTP_INTERCEPTORS } from '@angular/common/http';
...

@NgModule({
    ...
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: BlobErrorHttpInterceptor,
            multi: true
        },
    ],
    ...
export class CoreModule { }

Relaterade artiklar