Angular2 - HTTP
我们将用HTTPClient来添加一些数据持久化特效。
我们需要在App中启用HTTP服务,HttpClient是Angular通过http 与远程服务器通讯的机制。如果我们需要在整个App中使用并不需要重复导入。我们需要在AppModule顶层中从@angular/common/http 导入HttpClientModule 符号.
import { HttpClientModule } from '@angular/common/http'
并在加入@NgModule.imports 数组中。我们将可以在其他的Services中使用。并不需要重复导入。
给service创建一个从服务器获取数据的方法。
getHeroes(): Observable<object> { return this.http.get('http://localhost:8080/findByList/1', { headers: new HttpHeaders().set('Access-Control-Allow-Origin','*') }); }
我需要从服务器获取英雄列表,并返回Component显示。
在使用http的时候我们可以看到HttpClient 带有很多调用方式,Get , Post , Postion , Put , Delete 等。我们可以选择合适的方式调用API,常用的Get , Post。
在我们获取数据的时候。我们可能会遇到一些跨域,或者需要发送认证给客户端以便通过服务器认证。我们可以把这些消息写进heades中。
由于远程服务器不会马上应答或者得到服务器的结果。那么我们在Component中。使用结果就会由于异步原因而获取不到结果。所以我们需要告诉返回Observable 模式告诉Component , 当获取到服务器返回结果之后再做处理。
getHeroes(): Observable<Hero[]> { return this.http.get<Hero[]>('http://localhost:8080/findByList/1', { headers: new HttpHeaders().set('Access-Control-Allow-Origin','*') }); }
此方法会返回一个可广场的对象。只有再Component订阅此方法。方法才会执行,并在subscribe中处理返回结果。
//Component 中调用方式
this.heroesService.getHeroes() .subscribe(her => this.heroes = her);
当service没有返回数据或者不需要处理任何数据时。你只需要显示调subscribe即可
this.heroesService.getHeroes().subscribe();
可能有些人对Observable会感到陌生。RxJs也提供另一种方式Promise , 我们可以在 rxjs/operaters/toPromise中导入,并使用
getHeroes(): Promise<Hero[]> { return this.http.get('http://localhost:8080/findByList/1', { headers: new HttpHeaders().set('Access-Control-Allow-Origin','*') }).toPromise().then((response) = > {
console.log(response);//输出response
}); }
当我们在Component中调用getHeroes() 方法我们就可以在then中处理返回结果。
当然任何程序都有可能出现各种问题。特别是从远程服务器获取数据的时候。我们的方法应该捕获数据并做适当的处理。
要捕获错误。我们需要使用RxJS的catchError() 操作符来简历对Observable或者Primise的处理管道pipe。
import { catchError, map, tap } from 'rxjs/operators';
现在我们就可以使用pipe扩展Observable的结果。并给他一个catchError操作符。
getHeroes (): Observable<Hero[]> { return this.http.get<Hero[]>(this.heroesUrl) .pipe( catchError(this.handleError('getHeroes', [])) ); }
catchError() 操作符拦截失败的Observable,并把错误传给错误处理对象。所以我们把错误交给handleError。handleError(错误处理器)会处理这个错误。并返回一个无害的结果。以便应用能正常工作。
由于所有的HeroService方法都需要共享handleError方法。所以我们需要通用化错误处理器并且支持不同的需求。
/** * Handle Http operation that failed. * Let the app continue. * @param operation - name of the operation that failed * @param result - optional value to return as the observable result */ private handleError<T> (operation = 'operation', result?: T) { return (error: any): Observable<T> => { // TODO: send the error to remote logging infrastructure console.error(error); // log to console instead // TODO: better job of transforming error for user consumption this.log(`${operation} failed: ${error.message}`); // Let the app keep running by returning an empty result. return of(result as T); }; }
以上方法将返回一个安全值。让程序继续工作。
Service
的方法将会窥探 Observable
的数据流,并通过 log()
函数往页面底部发送一条消息。
它们可以使用 RxJS 的 tap
操作符来实现,该操作符会查看 Observable 中的值,使用那些值做一些事情,并且把它们传出来。 这种 tap
回调不会改变这些值本身。
/** GET heroes from the server */ getHeroes (): Observable<Hero[]> { return this.http.get<Hero[]>(this.heroesUrl) .pipe( tap(heroes => this.log('fetched heroes')), catchError(this.handleError('getHeroes', [])) ); }
AsyncPipe 如你所愿,*ngFor 重复渲染出了这些英雄。 仔细看,你会发现 *ngFor 是在一个名叫 heroes$ 的列表上迭代,而不是 heroes。
<li *ngFor="let hero of heroes$ | async" >
$ 是一个命名惯例,用来表明 heroes$ 是一个 Observable,而不是数组。 *ngFor 不能直接使用 Observable。 不过,它后面还有一个管道字符(|),后面紧跟着一个 async,它表示 Angular 的 AsyncPipe。 AsyncPipe 会自动订阅到 Observable,这样你就不用再在组件类中订阅了。