如何手动抛出可观察到的错误?

我正在开发一个 Angular 应用程序,我正在通过 HTTP 进行休息呼叫,如下所示:

login(email, password) {
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let options = new RequestOptions({ headers: headers });
let body = `identity=${email}&password=${password}`;
return this.http.post(`${this._configService.getBaseUrl()}/login`, body, options)
.map((res: any) => {
let response: any = JSON.parse(res._body);
if (response.success == 0) {
Observable.throw(response);  // not working
} else if (response.success == 1) {
console.log('success');
localStorage.setItem('auth_token', 'authenticated');
this.loggedIn = true;
return response;
}
});
}

基本上,我希望我的组件在我的订阅调用中得到响应和错误,即。

this._authenticateService.login(this.loginObj['identity'],this.loginObj['password']).subscribe(
(success)=>{
this.credentialsError=null;
this.loginObj={};
this._router.navigate(['dashboard']);
},
(error)=>{
console.log(error);
this.credentialsError=error;
}
);

但是我的 API 总是按照定义的方式返回成功。

如果是 response.success == 0,我如何抛出错误消息,以便在订阅回调的错误参数中访问它?

144527 次浏览

Use the catch operator

this.calcSub = this.http.post(this.constants.userUrl + "UpdateCalculation", body, { headers: headers })
.map((response: Response) => {
var result = <DataResponseObject>response.json();
return result;
})
.catch(this.handleError)
.subscribe(
dro => this.dro = dro,
() => this.completeAddCalculation()
);

And handle the error like this:

private handleError(error: Response) {
console.error(error); // log to console instead
return Observable.throw(error.json().error || 'Server Error');
}
if (response.success == 0) {
throw Observable.throw(response);
}

Edit for rxjs 6:

if (response.success == 0) {
throw throwError(response);
}

rxjs 5

Either

throw response;

or

throw Observable.throw(response);

rxjs 6

import { throwError } from 'rxjs';


if (response.success == 0) {
return throwError(response);
}

rxjs 5

import { ErrorObservable } from 'rxjs/observable/ErrorObservable';


if (response.success == 0) {
return new ErrorObservable(response);
}

What you return with ErrorObservable is up to you

Most of my issues were related to the imports, so here's the code that worked for me...

import {_throw} from 'rxjs/observable/throw';
login(email, password) {
...
return this.http.post(`${this._configService.getBaseUrl()}/login`, body, options)
.map((res: any) => {
...
if (response.success == 0) {
_throw(response);
} else if (response.success == 1) {
...
}
});
}

This will be the solution if you are facing errors like...

ERROR TypeError: WEBPACK_IMPORTED_MODULE_2_rxjs_Observable.Observable.throw is not a function

with rxjs 6

import { throwError } from 'rxjs';
throwError('hello');

Usually when you're throwing an error you'll be doing so at the exact moment the problem occurred and you want to raise it immediately, but this may not always be the case.

For instance there is the timeoutWith() operator, which is perhaps one of the most likely reasons you'll need to do this.

results$ = server.getResults().pipe(timeoutWith(10000, ....) )

This takes an 'error factory', which is a function.

 errorFactory = () => 'Your error occurred at exactly ' + new Date()

eg.

results$ = server.searchCustomers(searchCriteria).pipe(timeoutWith(10000,
() => 'Sorry took too long for search ' + JSON.stringify(searchCriteria)) )

Note that when using timeoutWith you'll never get the actual server response back - so if the server gave a specific error you'd never see it. This above example can be very useful in debugging, but be sure not to display the error to the end user if you use the above example.

AN error factory is helpful because it doesn't evaluate the code until the actual error occurs. So you can put 'expensive' or debugging operations inside that will get executed when the error is actually finally needed.

If you need to use a 'factory' to create your error somewhere other than in timeout you can use the following.

 EMPTY.pipe(throwIfEmpty(errorFactory))

Here is the official example (that emits number 7 and then error 'oops!'):

import { throwError, concat, of } from 'rxjs';


const result = concat(of(7), throwError(new Error('oops!')));
result.subscribe(x => console.log(x), e => console.error(e));

From: https://rxjs-dev.firebaseapp.com/api/index/function/throwError

rxjs 7

throwError(() => new Error(response))

more info https://rxjs.dev/deprecations/breaking-changes#throwerror

You can use catchError(error) => console.log(error) inside a pipe