激动人心的 Angular HttpClient的源码解析


Posted in Javascript onJuly 10, 2017

Angular 4.3.0-rc.0 版本已经发布?。在这个版本中,我们等到了一个令人兴奋的新功能 - HTTPClient API 的改进版本,以后妈妈再也不用担心我处理 HTTP 请求了?。

HttpClient 是已有 Angular HTTP API 的演进,它在一个单独的 @angular/common/http 包中。这是为了确保现有的代码库可以缓慢迁移到新的 API。

接下来让我们开启 Angular 新版Http Client 之旅。

安装

首先,我们需要更新所有的包到 4.3.0-rc.0 版本。然后,我们需要在 AppModule 中导入 HttpClientModule 模块。具体如下:

import { HttpClientModule } from '@angular/common/http';
@NgModule({
 declarations: [
  AppComponent
 ],
 imports: [
  BrowserModule,
  HttpClientModule
 ],
 bootstrap: [AppComponent]
})
export class AppModule { }

现在一切准备就绪。让我们来体验一下我们一直期待的三个新特性。

特性一 默认 JSON 解析

现在 JSON 是默认的数据格式,我们不需要再进行显式的解析。即我们不需要再使用以下代码:

http.get(url).map(res => res.json()).subscribe(...)

现在我们可以这样写:

http.get(url).subscribe(...)

特性二 支持拦截器 (Interceptors)

拦截器允许我们将中间件逻辑插入管线中。

请求拦截器 (Request Interceptor)

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

@Injectable()
class JWTInterceptor implements HttpInterceptor {
 
 constructor(private userService: UserService) {}
 
 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

  const JWT = `Bearer ${this.userService.getToken()}`;
  req = req.clone({
   setHeaders: {
    Authorization: JWT
   }
  });
  return next.handle(req);
 }
}

如果我们想要注册新的拦截器 (interceptor),我们需要实现 HttpInterceptor 接口,然后实现该接口中的 intercept 方法。

export interface HttpInterceptor {
 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>;
}

需要注意的是,请求对象和响应对象必须是不可修改的 (immutable)。因此,我们在返回请求对象前,我们需要克隆原始的请求对象。

next.handle(req) 方法使用新的请求对象,调用底层的 XHR 对象,并返回响应事件流。

响应拦截器 (Response Interceptor)

@Injectable()
class JWTInterceptor implements HttpInterceptor {

 constructor(private router: Router) {}
 
 intercept(req: HttpRequest < any > ,
  next: HttpHandler): Observable < HttpEvent < any >> {

  return next.handle(req).map(event => {
    if (event instanceof HttpResponse) {
     if (event.status === 401) {
      // JWT expired, go to login
     }
    }
    return event;
   }
  }
}

响应拦截器可以通过在 next.handle(req) 返回的流对象 (即 Observable 对象) 上应用附加的 Rx 操作符来转换响应事件流对象。

接下来要应用 JWTInterceptor 响应拦截器的最后一件事是注册该拦截器,即使用 HTTP_INTERCEPTORS 作为 token,注册 multi Provider:

[{ provide: HTTP_INTERCEPTORS, useClass: JWTInterceptor, multi: true }]

特性三 进度事件 (Progress Events)

进度事件可以用于跟踪文件上传和下载。

import {
 HttpEventType,
 HttpClient,
 HttpRequest
} from '@angular/common/http';

http.request(new HttpRequest(
 'POST',
  URL,
  body, 
 {
  reportProgress: true
 })).subscribe(event => {

 if (event.type === HttpEventType.DownloadProgress) {
  // {
  // loaded:11, // Number of bytes uploaded or downloaded.
  // total :11 // Total number of bytes to upload or download
  // }
 }

 if (event.type === HttpEventType.UploadProgress) {
  // {
  // loaded:11, // Number of bytes uploaded or downloaded.
  // total :11 // Total number of bytes to upload or download
  // }
 }

 if (event.type === HttpEventType.Response) {
  console.log(event.body);
 }
})

如果我们想要跟踪文件上传或下载的进度,在创建请求对象时,我们需要配置 {reportProgress: true} 参数。

此外在回调函数中,我们通过 event.type 来判断不同的事件类型,从进行相应的事件处理。

HttpEventType 枚举定义如下:

export enum HttpEventType {
 /**
  * 表示请求已经被发送
  */
 Sent,

 /**
  * 已接收到上传进度事件
  */
 UploadProgress,

 /**
  * 已接收到响应状态码和响应头
  */
 ResponseHeader,

 /**
  * 已接收到下载进度事件
  */
 DownloadProgress,

 /**
  * 已接收全部响应,包含响应体 
  */
 Response,

 /**
  * 用户自定义事件,来自拦截器或后端
  */
 User,
}

其实除了上面介绍三个新的功能之外,还有以下两个新的功能:

  1. 基于 Angular 内部测试框架的 Post-request verification 和 flush 功能
  2. 类型化,同步响应体访问,包括对 JSON 响应体类型的支持。

最后我们来通过 client_spec.ts 文件中的测试用例,来进一步感受一下上述的新特性。

其它特性

发送 GET 请求

describe('HttpClient', () => {
  let client: HttpClient = null !;
  let backend: HttpClientTestingBackend = null !;
  beforeEach(() => {
   backend = new HttpClientTestingBackend();
   client = new HttpClient(backend);
  });
  afterEach(() => { backend.verify(); }); // 请求验证
 
  describe('makes a basic request', () => {
   it('for JSON data', (done: DoneFn) => {
    client.get('/test').subscribe(res => {
     expect((res as any)['data']).toEqual('hello world');
     done();
    });
    backend.expectOne('/test').flush({'data': 'hello world'});
   });
   
   it('for an arraybuffer', (done: DoneFn) => {
    const body = new ArrayBuffer(4);
    // 还支持 {responseType: 'text'}、{responseType: 'blob'}
    client.get('/test', {responseType: 'arraybuffer'}).subscribe(res => {
     expect(res).toBe(body);
     done();
    });
    backend.expectOne('/test').flush(body);
   });
   
   it('that returns a response', (done: DoneFn) => {
    const body = {'data': 'hello world'};
    client.get('/test', {observe: 'response'}).subscribe(res => {
     expect(res instanceof HttpResponse).toBe(true);
     expect(res.body).toBe(body);
     done();
    });
    backend.expectOne('/test').flush(body);
   });
  });
});

发送 POST 请求

describe('makes a POST request', () => {
   it('with text data', (done: DoneFn) => {
    client.post('/test', 'text body', {observe: 'response', responseType: 'text'})
      .subscribe(res => {
       expect(res.ok).toBeTruthy();
       expect(res.status).toBe(200);
       done();
      });
    backend.expectOne('/test').flush('hello world');
   });
 
   it('with json data', (done: DoneFn) => {
    const body = {data: 'json body'};
    client.post('/test', body, {observe: 'response', 
     responseType: 'text'}).subscribe(res => {
     expect(res.ok).toBeTruthy();
     expect(res.status).toBe(200);
     done();
    });
    const testReq = backend.expectOne('/test');
    expect(testReq.request.body).toBe(body);
    testReq.flush('hello world');
   });
});

发送 JSONP 请求

describe('makes a JSONP request', () => {
   it('with properly set method and callback', (done: DoneFn) => {
    client.jsonp('/test', 'myCallback').subscribe(() => done());
    backend.expectOne({method: 'JSONP', url: '/test?myCallback=JSONP_CALLBACK'})
      .flush('hello world');
   });
});

参考资源

A Taste From The New Angular HTTP Client

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
看了就知道什么是JSON
Dec 09 Javascript
Javascript学习笔记8 用JSON做原型
Jan 11 Javascript
ASP.NET jQuery 实例5 (显示CheckBoxList成员选中的内容)
Jan 13 Javascript
javascript两种function的定义介绍及区别说明
May 02 Javascript
js父页面与子页面不同时显示的方法
Oct 16 Javascript
深入分析jsonp协议原理
Sep 26 Javascript
jquery拖拽效果完整实例(附demo源码下载)
Jan 14 Javascript
vue脚手架搭建过程图解
Jun 06 Javascript
vue监听input标签的value值方法
Aug 27 Javascript
3分钟了解vue数据劫持的原理实现
May 01 Javascript
JavaScript实现简易聊天对话框(加滚动条)
Feb 10 Javascript
Vue中使用JsonView来展示Json树的实例代码
Nov 16 Javascript
基于JS实现仿京东搜索栏随滑动透明度渐变效果
Jul 10 #Javascript
jQuery实现QQ空间汉字转拼音功能示例
Jul 10 #jQuery
Underscore之Array_动力节点Java学院整理
Jul 10 #Javascript
Angular.js ng-file-upload结合springMVC的使用教程
Jul 10 #Javascript
underscore之Collections_动力节点Java学院整理
Jul 10 #Javascript
Angular.js组件之input mask对input输入进行格式化详解
Jul 10 #Javascript
underscore之Chaining_动力节点Java学院整理
Jul 10 #Javascript
You might like
php清除和销毁session的方法分析
2015/03/19 PHP
php调用云片网接口发送短信的实现方法
2017/10/25 PHP
laravel5.6实现数值转换
2019/10/23 PHP
如何用js控制css中的float的代码
2007/08/16 Javascript
JavaScript 继承详解 第一篇
2009/08/30 Javascript
jquery.AutoComplete.js中文修正版(支持firefox)
2010/04/09 Javascript
基于jquery的复制网页内容到WORD的实现代码
2011/02/16 Javascript
jQuery关于导航条背景切换效果实现示例
2013/09/04 Javascript
Javascript改变CSS样式(局部和全局)
2013/12/18 Javascript
jquery实现手机端单店铺购物车结算删除功能
2017/02/22 Javascript
详解AngularJS用Interceptors来统一处理HTTP请求和响应
2017/06/08 Javascript
Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]的写法
2017/06/29 Javascript
实现单层json按照key字母顺序排序的示例
2017/12/06 Javascript
node.js通过axios实现网络请求的方法
2018/03/05 Javascript
Vue.js添加组件操作示例
2018/06/13 Javascript
在小程序Canvas中使用measureText的方法示例
2018/10/19 Javascript
在Vue中创建可重用的 Transition的方法
2020/06/02 Javascript
javascript+css实现俄罗斯方块小游戏
2020/06/28 Javascript
[11:57]《一刀刀一天》第十七期:TI中国军团加油!
2014/05/26 DOTA
padas 生成excel 增加sheet表的实例
2018/12/11 Python
使用python实现简单五子棋游戏
2019/06/18 Python
Python使用字典实现的简单记事本功能示例
2019/08/15 Python
python使用pip安装SciPy、SymPy、matplotlib教程
2019/11/20 Python
Pycharm中如何关掉python console
2020/10/27 Python
HTML5标签使用方法详解
2015/11/27 HTML / CSS
amazeui时间组件的实现示例
2020/08/18 HTML / CSS
手工制作的男士奢华英国鞋和服装之家:Goodwin Smith
2019/06/21 全球购物
SK-II神仙水美国官网:SK-II美国
2020/02/25 全球购物
解释一下ruby中的特殊方法与特殊类
2013/02/26 面试题
专科毕业生自我鉴定
2013/12/01 职场文书
超市中秋节活动方案
2014/02/12 职场文书
乡镇安全生产目标责任书
2014/07/23 职场文书
2014年惩防体系建设工作总结
2014/12/01 职场文书
基于Go语言构建RESTful API服务
2021/07/25 Golang
在虚拟机中安装windows server 2008的图文教程
2022/06/28 Servers
利用Python脚本写端口扫描器socket,python-nmap
2022/07/23 Python