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.
