In my Angular 4 app, I call a server's login api with http post. The server always responds with a stauts 200 whether or not the login was successful. I want to throw an error based on the server response data.
export class AuthenticationService {
...
login(username: string, password: string): Observable<any> {
let body = `method=login&username=${username}&password=${password}`;
return this.http.post('http://localhost/rest.php', body)
.map((response: Response) => {
let responsedata = response.json();
if (responsedata && responsedata.success == 1) {
localStorage.setItem('loggedin',1);
} else {
// Not logged in successfully
Observable.throw(new Error('Not logged in'));
}
});
}
And my code calling login()
trytologin() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
// Always returns here regarless of result of login
this.router.navigate([this.returnUrl]);
},
error => {
// ONLY returns here on a NON-server 200 status
this.alertService.error(error);
this.loading = false;
});
}
I think I could intercept the response and change the headers by using HttpInterceptor
, however this seems like overkill. Is there another way to get the subscribe
error to trigger from a 200 status response?
EDIT
I tried implementing a HttpInterceptor
without success.
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse,HttpHeaderResponse, HttpErrorResponse} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
@Injectable()
export class LoginInterceptor implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Need to .map so we can go through each event looking for the HttpResponse
// Can't use .do() as it doesn't update per the docs
return next.handle(req).map(event => {
if (event instanceof HttpResponse) {
let e2 = new HttpErrorResponse({status: 405, statusText: 'Auth error'});
// return Observable(e2); // Cannot return as HttpErrorResponse is NOT part of HttpEvent<any>
Observable.throw(e2); // <-- Still triggers the success in .subscribe(). Does NOT trigger the .subscribe() error
event = event.clone({status: 405, statusText: 'Auth error'}); // <-- change the event status. Can't return HttpErrorResponse as
}
return event;
});
}
}
The .subscribe()
success is always called.
EDIT #2
编辑#2
After LOTS of digging, I now know why my code was failing.
But I still don't have a solution!!
The
HttpInterceptor
is the way to go.....
but the Observer.throw() will only work
only if the HttpClient.post()
is on the same domain!!
The subscribe() error is called if I post() to localhost.
If I call a post() to another domain, it fails to call the subscribe() error.
I put a
console.log()
immediately after the
Observer.throw()
.
There is log output if I have a different domain.
There is
no log output if the domain is the same.
I don't know if this is a CORS issue as I have control over the server output and have included a
Access-Control-Allow-Origin: *
header item.
Is this possibly a bug in the
HttpClient
and/or
HttpInterceptor
???
Or maybe a problem with rxjs??
Edit #3
If I simply return an Observable.throw()
in the intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
block my error code gets triggered. This however will trigger on the http request only. I need to process and throw an error on the . 上引发错误。 In order to do this I need to use return next.handle(req).map()
to look for each HttpResponse
event.
If I try and execute an Observer.throw()
inside the map()
it does NOT trigger my error code and is not caught anywhere. The line after the Observer.throw()
is executed.
I can't return Observer.throw()
from the map()
as it is the incorrect return type.
However, calling a plain javascript throw()
inside of the map()
will trigger my error code.
I'm not sure if a plain throw()
is best practice or if I should be doing something else.
You will have to import proper libraries and methods of Observable to get this code working like
import { HttpInterceptor, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/Observable/of';
You can intercept the response and from that response you can take a decision,
export class YourInterceptor implements HttpInterceptor{
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>{
//check your conditions if fall true send this response as given //below
return Observable.throw(new HttpErrorResponse({status:401, statusText:"Error of auth"}));
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.