如何正确地从 http.request()捕获异常?

我代码的一部分:

import {Injectable} from 'angular2/core';
import {Http, Headers, Request, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';


@Injectable()
export class myClass {


constructor(protected http: Http) {}


public myMethod() {
let request = new Request({
method: "GET",
url: "http://my_url"
});


return this.http.request(request)
.map(res => res.json())
.catch(this.handleError); // Trouble line.
// Without this line code works perfectly.
}


public handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}


}

myMethod()在浏览器控制台中产生异常:

原始异常: TypeError: this.http.request (...) . map (...) . catch 不是函数

299085 次浏览

也许你可以尝试在你的进口商品中加入以下内容:

import 'rxjs/add/operator/catch';

你也可以这样做:

return this.http.request(request)
.map(res => res.json())
.subscribe(
data => console.log(data),
err => console.log(err),
() => console.log('yay')
);

每条评论:

例外: TypeError: Observatory able _ 1. Observer able.throw 不是一个函数

类似地,你可以使用:

import 'rxjs/add/observable/throw';

需要专门导入 RxJS 函数。一个简单的方法是用 import * as Rx from "rxjs/Rx"导入它的所有特性

然后确保以 Rx.Observable的形式访问 Observable类。

更新了使用 HttpClientModule 和 RxJS v5.5. x的新服务:

import { Injectable }                    from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable }                    from 'rxjs/Observable';
import { catchError, tap }               from 'rxjs/operators';
import { SomeClassOrInterface}           from './interfaces';
import 'rxjs/add/observable/throw';


@Injectable()
export class MyService {
url = 'http://my_url';
constructor(private _http:HttpClient) {}
private handleError(operation: String) {
return (err: any) => {
let errMsg = `error in ${operation}() retrieving ${this.url}`;
console.log(`${errMsg}:`, err)
if(err instanceof HttpErrorResponse) {
// you could extract more info about the error if you want, e.g.:
console.log(`status: ${err.status}, ${err.statusText}`);
// errMsg = ...
}
return Observable.throw(errMsg);
}
}
// public API
public getData() : Observable<SomeClassOrInterface> {
// HttpClient.get() returns the body of the response as an untyped JSON object.
// We specify the type as SomeClassOrInterfaceto get a typed result.
return this._http.get<SomeClassOrInterface>(this.url)
.pipe(
tap(data => console.log('server data:', data)),
catchError(this.handleError('getData'))
);
}

旧服务,它使用已废弃的 HttpModule:

import {Injectable}              from 'angular2/core';
import {Http, Response, Request} from 'angular2/http';
import {Observable}              from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
//import 'rxjs/Rx';  // use this line if you want to be lazy, otherwise:
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';  // debug
import 'rxjs/add/operator/catch';


@Injectable()
export class MyService {
constructor(private _http:Http) {}
private _serverError(err: any) {
console.log('sever error:', err);  // debug
if(err instanceof Response) {
return Observable.throw(err.json().error || 'backend server error');
// if you're using lite-server, use the following line
// instead of the line above:
//return Observable.throw(err.text() || 'backend server error');
}
return Observable.throw(err || 'backend server error');
}
private _request = new Request({
method: "GET",
// change url to "./data/data.junk" to generate an error
url: "./data/data.json"
});
// public API
public getData() {
return this._http.request(this._request)
// modify file data.json to contain invalid JSON to have .json() raise an error
.map(res => res.json())  // could raise an error if invalid JSON
.do(data => console.log('server data:', data))  // debug
.catch(this._serverError);
}
}

我使用 .do()(现在是 .tap())进行调试。

当出现服务器错误时,我从正在使用的服务器(lite-server)获得的 Response对象的 body只包含文本,因此我使用上面的 err.text()而不是 err.json().error的原因。您可能需要为服务器调整该行。

如果 res.json()由于无法解析 JSON 数据而引发错误,那么 _serverError将不会得到 Response对象,因此需要进行 instanceof检查。

在此 plunker中,将 url更改为 ./data/data.junk以生成错误。


任何一个服务的用户都应该有能够处理错误的代码:

@Component({
selector: 'my-app',
template: '<div>\{\{data}}</div>
<div>\{\{errorMsg}}</div>`
})
export class AppComponent {
errorMsg: string;
constructor(private _myService: MyService ) {}
ngOnInit() {
this._myService.getData()
.subscribe(
data => this.data = data,
err  => this.errorMsg = <any>err
);
}
}

在最新版本的 angular4使用

import { Observable } from 'rxjs/Rx'

它会导入所有需要的东西。

有几种方法可以做到这一点。两者都很简单。每个例子都很好用。您可以将其复制到项目中并对其进行测试。

第一种方法更可取,第二种方法有点过时,但到目前为止它还是有效的。

1)解决方案1

// File - app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';


import { AppComponent } from './app.component';
import { ProductService } from './product.service';
import { ProductModule } from './product.module';


@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [ProductService, ProductModule],
bootstrap: [AppComponent]
})
export class AppModule { }






// File - product.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';


// Importing rxjs
import 'rxjs/Rx';
import { Observable } from 'rxjs/Rx';
import { catchError, tap } from 'rxjs/operators'; // Important! Be sure to connect operators


// There may be your any object. For example, we will have a product object
import { ProductModule } from './product.module';


@Injectable()
export class ProductService{
// Initialize the properties.
constructor(private http: HttpClient, private product: ProductModule){}


// If there are no errors, then the object will be returned with the product data.
// And if there are errors, we will get into catchError and catch them.
getProducts(): Observable<ProductModule[]>{
const url = 'YOUR URL HERE';
return this.http.get<ProductModule[]>(url).pipe(
tap((data: any) => {
console.log(data);
}),
catchError((err) => {
throw 'Error in source. Details: ' + err; // Use console.log(err) for detail
})
);
}
}

2)解决方案2。这是老办法,但仍然有效。

// File - app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';


import { AppComponent } from './app.component';
import { ProductService } from './product.service';
import { ProductModule } from './product.module';


@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpModule
],
providers: [ProductService, ProductModule],
bootstrap: [AppComponent]
})
export class AppModule { }






// File - product.service.ts
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';


// Importing rxjs
import 'rxjs/Rx';
import { Observable } from 'rxjs/Rx';


@Injectable()
export class ProductService{
// Initialize the properties.
constructor(private http: Http){}


// If there are no errors, then the object will be returned with the product data.
// And if there are errors, we will to into catch section and catch error.
getProducts(){
const url = '';
return this.http.get(url).map(
(response: Response) => {
const data = response.json();
console.log(data);
return data;
}
).catch(
(error: Response) => {
console.log(error);
return Observable.throw(error);
}
);
}
}