@angular/common/http中的HttpClient类,Angular 为应用程序提供了一个简化的 API 来实现 HTTP 功能。它基于浏览器提供的XMLHttpRequest接口。 HttpClient带来的其它优点包括:可测试性、强类型的请求和响应对象、发起请求与接收响应时的拦截器支持,以及更好的、基于可观察(Observable)对象的错误处理机制。

安装本模块

import {HttpClientModule} from '@angular/common/http';  imports: [
    BrowserModule,
    // Include it under 'imports' in your application module
    // after BrowserModule.
    HttpClientModule,
  ],
{
  "results": [
    "Item 1",
    "Item 2",
  ]
}
//HttpClient的get()方法可以让访问此数据的代码非常直白:

    this.http.get('/api/items').subscribe(data => {
      // Read the result field from the JSON response.
      this.results = data['results'];  (写成data.results,TypeScript 就会抱怨说来自HTTP的Object没有一个名叫results的属性)
    });

  

响应体的类型检查

上面的例子中,访问data['results']是用方括号语法来取得results字段的。如果写成data.results,TypeScript 就会抱怨说来自HTTP的Object没有一个名叫results的属性。 那是因为HttpClient把 JSON 格式的响应体解析成了一个Object,它并不知道这个对象的形态应该是什么。

其实可以告诉HttpClient这个响应体应该是什么类型的,而且这是推荐的做法。 要这样做,首先我们要定义一个接口来描述这个类型的正确形态:

interface ItemsResponse {
  results: string[];
}

http.get<ItemsResponse>('/api/items').subscribe(data => {
  // data is now an instance of type ItemsResponse, so you can do this:
  this.results = data.results;
});

  

读取完整的响应体

通过observe选项来告诉HttpClient,你想要完整的响应信息,而不是只有响应体:

http
  .get<MyJsonData>('/data.json', {observe: 'response'})
  .subscribe(resp => {
    console.log(resp.headers.get('X-Custom-Header'))
    console.log(resp.body.someField);
  });

  

错误处理

http
  .get<ItemsResponse>('/api/items')
  .subscribe(
    // Successful responses call the first callback.
    data => {...},
    // Errors will call this callback instead:
    err => {
      console.log('Something went wrong!');
    }
  );

  

.retry() 操作符

这种策略对于那些临时性的而且不大可能重复发生的错误会很有用

http
  .get<ItemsResponse>('/api/items')
  // Retry this request up to 3 times.
  .retry(3)
  // Any errors after the 3rd retry will fall through to the app.
  .subscribe(...);

  

请求非 JSON 数据

http
  .get('/textfile.txt', {responseType: 'text'})
  .subscribe(data => console.log(data));

  

把数据发送到服务器

发起一个 POST 请求

const body = {name: 'Brad'};
http.post('/api/developers/add', body).subscribe(...);

  

注意这个subscribe()方法。 所有从HttpClient返回的可观察对象都是冷的(cold),也就是说,它们只是发起请求的蓝图而已。在我们调用subscribe()之前,什么都不会发生,而当我们每次调用subscribe()时,就会独立发起一次请求。 比如,下列代码会使用同样的数据发送两次同样的 POST 请求:

const req = http.post('/api/items/add', body);
// 0 requests made - .subscribe() not called.
req.subscribe();
// 1 request made.
req.subscribe();
// 2 requests made

  

配置请求中的其它部分

除了 URL 和可能的请求体之外,要发送的请求中你可能还希望配置一些别的东西。所有这些都可以通过给这次请求传一个额外的options(选项)对象来解决

http
  .post('/api/items/add', body, {
    headers: new HttpHeaders().set('Authorization', 'my-auth-token'),
  })
  .subscribe();

HttpHeaders类是不可变对象(immutable),所以每个set()都会返回一个新实例,并且应用上这些修改

URL 参数

http
  .post('/api/items/add', body, {
    params: new HttpParams().set('id', '3'),
  })
  .subscribe();

这种情况下,我们会往 URL /api/items/add?id=3 上发送一个 POST 请求

拦截所有的请求和响应。

@angular/common/http的主要特性之一是拦截器,它能声明一些拦截器,拦在应用和后端之间。当应用程序发起一个请求时,拦截器可以在请求被发往服务器之前先转换这个请求。并且在应用看到服务器发回来的响应之前,转换这个响应。这对于处理包括认证和记录日志在内的一系列工作都非常有用。

写一个拦截器

要实现一个拦截器,就要声明一个实现了HttpInterceptor接口的类,它只有一个intercept()方法。下面是一个最简单的拦截器,它什么也不做,只是简单的转发请求而不做任何修改:

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

@Injectable()
export class NoopInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req);
  }
}

  

intercept是一个方法,它把一个请求对象转换成一个返回这个响应的可观察对象(Observable)

当然,大多数时候,拦截器会对请求做一些小的修改,然后才把它转给拦截器链中的其它部分,也就是所传进来的next参数。next是一个HttpHandler,是一个类似于intercept的接口,它会把一个请求对象转换成一个可观察的响应对象。在拦截器中,next总是代表位于拦截器链中的下一个拦截器(如果有的话),如果没有更多拦截器了,它就会是最终的后端。所以,大多数拦截器的最后一句都会以它们转换后请求对象为参数调用next.handle函数。

像上面这样简单地声明NoopInterceptor并不会让我们的应用实际使用它。还要通过把它作为拦截器提供给我们的应用模块才会生效,代码如下:

import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';

@NgModule({
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: NoopInterceptor,
    multi: true,
  }],
})
export class AppModule {}

  

注意multi: true选项。这是必须的,因为它会告诉 Angular 这个 HTTP_INTERCEPTORS 表示的是一个数组,而不是单个的值。

顺序

当我们在一个应用中提供了多个拦截器时,Angular 会按照你提供时的顺序应用它们(译注:即模块的providers数组中列出的顺序)。

不可变性

拦截器要检查和修改准备发出的请求和接收进来的响应。但是,你可能会惊奇的发现HttpRequestHttpResponse类在很大程度上却是不可变的。

因为应用可能会重发请求,而拦截器链可能会多次处理同一个请求。如果请求是可变的,每次重试时的请求都可能和原始的请求不一样。而不可变对象可以确保拦截器每次重试时处理的都是同一个请求。

如果确实需要修改请求体,我们就得自己复制它,修改这个复本,然后使用clone()来复制这个请求,并使用这个新的请求体。

由于请求都是不可变的,所以不能直接修改它们。要想修改,就使用clone()函数:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  // This is a duplicate. It is exactly the same as the original.
  const dupReq = req.clone();
  const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
}

  

设置新的头

拦截器的常见用途之一是为所发出的请求设置默认的请求头。比如,假设我们有一个可注入的AuthService,它可以提供一个认证令牌,而我们希望写一个拦截器,它负责把这个令牌添加到所有要发出的请求中:

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const authHeader = this.auth.getAuthorizationHeader();
    const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});   //简写: const authReq = req.clone({setHeaders: {Authorization: authHeader}});
    return next.handle(authReq);
  }
}

这种可以修改头的拦截器可以用于很多不同的操作,比如:

    • 认证 / 授权

    • 控制缓存行为。比如If-Modified-Since

    • XSRF 防护

angular2-HttpClient的更多相关文章

  1. Angular2 HttpClient (一)

    @angular/common/http 中的 HttpClient 类为 Angular 应用程序提供了一个简化的 API 来实现 HTTP 客户端功能.它基于浏览器提供的 XMLHttpReque ...

  2. Angular2学习笔记一

    TypeScript: TypeScript变量声明:let和const是JavaScript里相对较新的变量声明方式,const是对let的一个增强,它能阻止对一个变量再次赋值. var作用域或函数 ...

  3. Angular2 Service获取json数据

    在Angular2框架下一般交互解析json是要用到Service的,其实除了Service还是很多的,今天先写个最简单的前后端数据交互 嗯~~ 首先我先在app包下直接创建Service 好了 这里 ...

  4. Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求

    上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...

  5. Angular2学习笔记(1)

    Angular2学习笔记(1) 1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之 ...

  6. Angular杂谈系列1-如何在Angular2中使用jQuery及其插件

    jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...

  7. Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数

    上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...

  8. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  9. Angular2入门系列教程4-服务

    上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得 ...

  10. Angular2入门系列教程3-多个组件,主从关系

    上一篇 Angular2项目初体验-编写自己的第一个组件 好了,前面简单介绍了Angular2的基本开发,并且写了一个非常简单的组件,这篇文章我们将要学会编写多个组件并且有主从关系 现在,假设我们要做 ...

随机推荐

  1. 【sql server】"已更新或删除的行值要么不能使该行成为唯一行,要么改变了多个行" 解决方案

    #事故现场: 1.在手动修改某表中数据是,出现如下错误提示:  已更新或删除的行值要么不能使该行成为唯一行,要么改变了多个行 2.表结构及数据: #解决方法: 1.原因分析:提示被删除的行不是唯一行, ...

  2. QRCode简介(收藏)

      一.什么是二维码:二维码 (2-dimensional bar code),是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的. 在许多种类的二维条码中,常 ...

  3. ORACLE的WITH语句的一个疑惑

    使用WITH语句,更新表数据,不行: WITH VN AS ( SELECT T.ID, T.NODE_ID, N.NODE_TYPE, N.NODE_NAME, T.NODE_LEVEL, T.RN ...

  4. 2019年华南理工大学程序设计竞赛(春季赛) K Parco_Love_String(后缀自动机)找两个串的相同字串有多少

    https://ac.nowcoder.com/acm/contest/625/K 题意: 给出Q 个询问 i , 求 s[0..i-1] 与 s[i...len-1] 有多少相同的字串 分析: 给出 ...

  5. 2018牛客多校1 - J Different Integers 莫队/主席树签到

    题意:给出n<5e4,a[1...n],单次1e5总次1e6次查询除去区间(L,R)的数的个数 开场5分钟:莫队是不可能莫队的,这道题是不可能莫队的 最后1小时:真香 具体操作没啥特别的,注意一 ...

  6. portmap安装

  7. 算法导论学习笔记1---排序算法(平台:gcc 4.6.7)

    平台:Ubuntu 12.04/gcc 4.6.7 插入排序 #include<vector> #include <algorithm> #include<iostrea ...

  8. php添加mysql.so扩展

    1.软件包安装 yum install php-mysql 安装的是mariadb的扩展 yum install php-mysqlnd 安装的是mysql的扩展

  9. 【ExtJS】FormPanel表单验证

    在Extjs中,FormPane表单提供了各种各样的验证. 在表单验证前需要在onReady的function({})内添加以下代码: Ext.QuickTips.init();    //为组件提供 ...

  10. eclipspe导入hibernate的源代码

    看图: