angular - Angular2/Rxjs: 'catch' på observable gir ProgressEvent i stedet for json fra respons


I min HttpServive har jeg delt http-metoder som vil håndtere start/slutt av lastestangen, sette de riktige overskriftene for JWT, og så videre.

Alt er fint, men nå prøver jeg å legge til litt logikk i catch for å sjekke responsen i tilfelle en ikke-200 statuskode (som for eksempel 401), slik at jeg kan gjøre noe og deretter gjøre forespørselen som feilet på nytt.

Problemet er at svaret jeg får tilbake ved en ikke-200 statuskode ikke er tilgjengelig fra den catch av en eller annen grunn.

For eksempel, dette er koden:

// ...

return this.http[method](url, options || defaultOptions)
    .map((res: Response) => res.json()) // <--- gives JSON from response
    .catch((error: any)) => {
        console.log(error);
        console.log(error.json()); // <--- should give JSON from response, but gives ProgressEvent instead
        return Observable.throw(error.json()); // also gives ProgressEvent when I 'subscribe' to the observable
    })
    .finally(() => {
        this.loadingBarService.complete();
    });

console.log(error) skriver ut feilen av typen Response; console.log(error.json()) skriver ut noen data av typen ProgressEvent.

Hvorfor får jeg en ProgressEvent, i stedet for JSON-en som ble sendt fra svaret med en ikke-200 statuskode?

Dette er ProgressEvent:

{
    bubbles: false,
    cancelBubbles: false,
    cancelable: false,
    composed: false,
    currentTarget: XMLHttpRequest,
    defaultPrevented: false,
    eventPhase: 0,
    isTrusted: true,
    lengthComputable: false,
    loaded: 0,
    path: Array(0),
    returnValue: true,
    srcElement: XMLHttpRequest,
    target: XMLHttpRequest,
    timeStamp: 1234.115,
    total: 0,
    type: "error",
    __proto__: ProgressEvent
}

Som du kan se, er ProgressEvent ikke mitt svar. Mitt svar er et JSON-objekt med bare én error-egenskap, som inneholder en melding og en status. Dette er bare feil, hvorfor får jeg ikke mitt svar?

Svar #1

Jeg har et lignende problem når jeg jobber på et spa-prosjekt basert på Angular og Asp.Net Core.

Hvis det er det samme problemet, bør det ha avhengig av mangelen på CORS-headere i HTTP-responsen som klienten mottar fra serveren. Denne responsen bryter nettleserens CORS-policy og avhenger mest sannsynlig av ikke håndterte kjøretidsfeil i serveren.

Selv ved å fange alle feil og legge inn noe informasjon og HTTP-status i responsen som returneres, tillater ikke Angular, når det oppstår brudd på CORS-begrensninger, tilgang til noen informasjon fra responsen, ikke engang HTTP-statusen, og derfor produserer den den «tomme» responsen:

Response {_body: ProgressEvent, status: 0, ok: false, statusText: "", headers: Headers, …} headers : Headers {_headers: Map(0), _normalizedNames: Map(0)} ok : false status : 0 statusText : "" type : 3 url : null..

Jeg løste dette problemet ved å legge CORS-headere inn i responsen som returneres av ASp.Net Core API-serveren til klienten på denne måten:

   app.UseExceptionHandler(appError => {
                appError.Run(async context => {

                    var _config = ServiceProviderFactory.ServiceProvider.GetService<AppConfigurations>();

                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    context.Response.ContentType = "application/json";
                    context.Response.Headers.Add("Access-Control-Allow-Origin", $"{_config.AngularSiteUrl}");
                    context.Response.Headers.Add("Access-Control-Allow-Headers", "access-control-allow-origin,authorization,content-type");

                    var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
                    if (contextFeature != null) {

                        var ex = contextFeature.Error;

                        var sp = services.BuildServiceProvider();
                        var _logger = sp.GetService<IGenericRepository<Log>>();

                        _logger.AddAndSave(new Log {
                            Description = "Exception not handled occurred",
                            Reason = ex.ToString(),
                            Type = "Error"
                        });

                         await context.Response.WriteAsync(
                            JsonConvert.SerializeObject(new {
                            Status = context.Response.StatusCode,
                            Message = "Internal Server Error."
                        }));
                    }
                });

Koden må settes inn i Configure-metoden i Startup-klassen.

Jeg håper at det kan være til hjelp.

Relaterte artikler