Angular 5 建立 HttpClient 与后台通信

近年来,前端开发变得越来越复杂,特别是与后台通信的方面。没有一个优秀的库来支持这一方面的开发,很多开发者只能使用浏览器自带的 XMLHttpRequest 或者 JQuery 的 ajax 方法来实现与后台的通信。这种方法会让前端开发变得混乱,不易维护。Angular 5 发布了一个新的库来处理这一方面的问题,它是 HttpClient 。

HttpClient 概述

HttpClient 是 Angular 5 中用来处理和后台交互的库。它的 API 是面向流的,它支持 JSON 格式的数据以及类型,还能处理 HTTP 请求和响应,缓存机制并支持拦截器。HttpClient 是 Angular 的一部分,所以如果你使用 Angular,HttpClient 就已经存在于你的工程中了。

HttpClient 的使用

前提:假设有一个后台服务,它有一个 GET 方法,它返回 JSON 类型的数据。

第一步,导入 HttpClient 模块。

import { HttpClientModule } from '@angular/common/http';

第二步,在 AppModule 中配置 HttpClient 模块。

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

第三步,实现一个服务来处理请求。

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class DataService {

  constructor(private http: HttpClient) { }

  getData() {
    return this.http.get('/api/data');
  }

}

getData 方法向后台发送一个 GET 请求,它请求的地址是 '/api/data' ,并返回一个 RxJS 可观察对象。RxJS 是 Angular 中用来处理异步数据流的框架。

第四步,订阅可观察对象并处理响应。

import { Component } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-root',
  template: `
    <ul>
      <li *ngFor="let item of data">{{ item }}</li>
    </ul>
  `,
})
export class AppComponent {

  data: any[];

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.dataService.getData().subscribe(data => {
      this.data = data;
    });
  }

}

这里,我们在 AppComponent 中订阅了可观察对象,并在响应到达时更新了列表。

HttpClient 格式

HttpClient 提供了一系列的方法来处理不同的 HTTP 请求方法。这些方法分别是:

  • delete
  • get
  • head
  • jsonp
  • options
  • patch
  • post
  • put

这些方法的参数都相同,都是一个字符串类型的 url ,和一个可选的 options 对象。options 对象包含一些方法特有的参数。这个对象中的常见属性有:

  • headers:请求头的配置。
  • observe:指定响应类型的观察者类型。
  • params:请求参数。
  • reportProgress:是否报告上传或下载的进度。
  • responseType:响应的类型。
  • withCredentials:是否跨域请求。

HttpClient 的错误处理

当请求出错时,HttpClient 会返回一个错误信息的可观察对象。如果你希望应用程序可以处理错误,你应该订阅错误信息。你可以使用 catchError 操作符来处理这些错误。

import { Component } from '@angular/core';
import { DataService } from './data.service';
import { catchError } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  template: `
    <div *ngIf="errorMessage" class="error">{{ errorMessage }}</div>
    <ul *ngIf="data">
      <li *ngFor="let item of data">{{ item }}</li>
    </ul>
  `,
})
export class AppComponent {

  errorMessage: string;
  data: any[];

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.dataService.getData().pipe(
      catchError((error) => {
        this.errorMessage = '请求失败,请重试。';
        return [];
      })
    ).subscribe(data => {
      this.data = data;
    });
  }

}

在这个例子中,我们利用了 catchError 操作符来处理错误。当 handleError 被执行时,我们简单地将 errorMessage 赋值为一个适当的错误消息,并将 data 赋值为空数组。

HttpClient 的拦截器

在我们的应用程序中,我们可能需要在所有 HTTP 请求之前执行某些操作,例如添加身份验证信息。这正是 HTTP 拦截器的用武之地。

为了添加一个拦截器,我们首先需要定义一个拦截器类。

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    intercept(req: HttpRequest<any>, next: HttpHandler) {
      const authToken = 'my-auth-token';
      const authReq = req.clone({
        headers: req.headers.set('Authorization', authToken)
      });
      return next.handle(authReq);
    }

}

在这个例子中,我们定义了一个 AuthInterceptor。它实现了 HttpInterceptor 接口,接口要求我们实现一个拦截方法 intercept 。intercept 方法首先检查是否有一个有效的身份验证令牌,如果有则将其添加到请求的 headers 中,同时克隆该请求。最后,返回处理函数的下一个函数的 handle 方法所返回的 observable。

这个 AuthInterceptor 类仅仅是一个简单的例子,你可以根据你的需要来添加更多的拦截器。

为了让 HttpClient 在每个请求中加入我们的拦截器,我们必须在 AppModule 中的 HttpClient 模块引入时添加拦截器类。

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth-interceptor';

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

在这个例子中,我们添加了一个 HTTP_INTERCEPTORS 依赖注入提供程序,并通过它来添加 AuthInterceptor 来指定我们要添加的拦截器类。multi 属性是必需的,因为我们可能有多个拦截器。

HttpClient 的缓存机制

HttpClient支持缓存响应数据,以便下一次调用该请求时,可以在不重新执行整个请求的情况下返回该响应。这可以提高应用程序的响应速度。

为了实现缓存,我们需要导入 HttpClient 的 HttpCacheService。

import { HttpCacheService } from './http-cache.service';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { CachingInterceptor } from './caching-interceptor';

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    HttpCacheService,
    { provide: HTTP_INTERCEPTORS, useClass: CachingInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

然后我们需要实现一个 CachingInterceptor 类。

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { tap } from 'rxjs/operators';
import { HttpCacheService } from './http-cache.service';

@Injectable()
export class CachingInterceptor implements HttpInterceptor {
  constructor(private cacheService: HttpCacheService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // 如果请求不可缓存,则将其传递给处理程序并返回它的结果。
    if (req.method !== 'GET') {
      return next.handle(req);
    }
    // 如果请求在缓存中,则返回缓存响应。
    const cachedResponse = this.cacheService.get(req);
    if (cachedResponse) {
        return Observable.of(cachedResponse);
    }
    // 请求网络数据,并缓存响应。
    return next.handle(req)
      .pipe(
        tap(event => {
        if (event instanceof HttpResponse) {
            this.cacheService.put(req, event);
        }
      })
    );
  }
}

CachingInterceptor 来管理我们的缓存。 在拦截器的构造函数中,我们注入了一个名为 HttpCacheService 的服务。 对于单个请求,它首先检查缓存是否包含请求的响应数据。如果缓存了该响应,则它会立即返回缓存的响应。否则,它会将请求传递给处理程序,等待网络响应,并缓存响应以供以后使用。

总结

HttpClient 是 Angular 中用来处理和后台交互的库。 它支持 JSON 数据,处理 HTTP 请求和响应,并支持拦截器。除此之外,HttpClient还支持缓存机制、异常处理等。通过学习这些内容,我们可以掌握如何顺畅地将Angular应用程序与服务器集成起来。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a6241aadd4f0e0ffed2afd


纠错反馈