详解使用angular的HttpClient搭配rxjs


Posted in Javascript onSeptember 01, 2017

一、原Http使用总结

使用方法

1.在根模块或核心模块引入HttpModule

即在AppModule或CoreModule中引入HttpModule:

import { HttpModule } from '@angular/http';
@NgModule({
 import: [ HttpModule ]
 // ...
})
AppModule {}

2.在使用的地方注入Http服务

import { Http } from '@angular/http';
// ...
constructor(
 private http: Http
) {}
ngOnInit() {
 this.http.get(`url`).subscribe((res) => {
// 成功回调
 }, (err) => {
// 失败回调
 });
}
// ...

3.使用可选参数

 若想在请求中添加特定的头部或者身体,就需要配置请求的可选参数:

import { Http, Header } from '@angular/http';
// ...
this.http.delete(`url`, {headers: new Header(), body: { } }).subscribe(...);
// ...

缺陷

已知缺陷之一为不支持文件传输,如果想要写一个文件上传的客户端,就只能使用JS原生的XMLHttpRequest对象,然后自己封装上rxjs得到一个较通用的文件上传服务,可以参考 ngx-uploader。

另一个不能算缺陷的缺陷是Http请求得到的响应结果必须手动执行json()以得到json格式的结果。

二、改用HttpClient

HttpClient能力在angular 4.3版本开始引入在@angular/common/http中

使用方法

基本使用方法与原Http服务类似,先引入HttpClientModule,然后注入HttpClient服务使用:

import { HttpClientModule } from '@angular/common/http';
// ...
@NgModule({
 import: [ HttpClientModule ]
})
// ...
import { HttpClient } from '@angular/common/http';
// ...
constructor(
 private http: HttpClient
) {}
// ...
this.http.get('url').subscribe((res) => {
 // 成功回调
}, (err) => {
 // 失败回调
});
// ...

添加额外头部等信息的话类似原Http服务,引入相关的变量后填入第二个可选参数即可。

改进与加强

1.支持更多类型的请求,比如更改可选参数的responseType值可改为直接请求text内容
2.不再需要手动调用json()来将结果转为json格式,订阅到的结果已经是body且转为了json(请求text的话直接就是text内容)。
3.支持监听请求进度(可用于文件上传)。
4.添加了拦截器能力,用于预设请求规则和响应预处理。

缺陷

已知的一个小缺陷是,delete请求不能再添加body作为可选参数了,这个略尴尬,难道批量删除也得乖乖把参数拼到url中。。。

三、拦截器

本文暂不讨论文件上传以及请求进度的监听能力,可以查看官网的相关内容,本文主要来讲拦截器的简单使用。

给应用注入拦截器的效果是,所有的HttpClient发起的请求都将执行这个拦截器,类似Node中的中间件。且无论是请求之前的预处理还是得到响应后的预处理都能做到。

笔者想到的第一个用处就是不再需要写一个自己的Http服务来代执行angular的Http服务了,以往如果想要给应用的所有请求都添加比如认证功能的请求头的话,比较好的办法就是自己建立一个MyHttp服务来代为调用Http方法,并在请求回调中添加统一的结果处理。

拦截器属于特殊服务,实现了HttpInterceptor类:

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

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

编辑好拦截器后需要注入到根模块中:

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

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

预处理请求

所有工作都在拦截器中的intercept方法中进行,如果要给所有请求加一个认证头部,可以操作其中的req参数,注意req参数为只读的,必须执行其clone方法得到副本来操作,处理完的副本通过next参数发射出去即可:

public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
 let authInfo = {token: 'testtoken', admin: 'testadmin'};
 const authReq = req.clone({
  headers: req.headers
  .set('Authorization', authInfo.token || '')
  .set('Admin', authInfo.admin || '')
  .set('Content-Type', 'application/json;charset=UTF-8')
 });
 return next.handle(authReq);
}

这样实际使用请求时可以直接使用HttpClient,所有请求都会实现添加配置好的头部信息。

响应预处理

请求得到结果后,往往需要对结果进行一些判断,比如某些错误是请求本身的错误,这些错误会直接抛出到rxjs的error流中,某些请求本身是成功的,但是是属于一些服务器逻辑给出的错误,这类错误如果不做处理是会被认为是成功的请求而直接next到成功回调的,这会导致最终订阅请求时,错误的回调要做错误处理,成功回调中也存在需要做错误处理,感觉成功还得分为成功地成功和成功地失败,很尴尬:

someReq().subscribe((res) => {
 if (res.state) {
 // 真正成功
 } else {
 // 还是失败
 }
}, (err) => {
 // 失败
});

通过拦截器可以对请求结果进行重新整理,保证成功回调必然成功,失败回调必然失败:

return next.handle(authReq).map((event) => {
 if (event instanceof HttpResponse) {
 switch (event.status) {
  case 200:
  if (event.body['state']) {
  let newEvent = event.clone({body: event.body['data']});
  return newEvent;
  } else {
  throw event.body['msg'];
  }
  case 401:
  this.storage.remove('auth_token');
  this.router.navigate(['/login']);
  default:
  throw `【${event.status}】【${event.statusText}】`;
 }
 }
 return event;
});

响应预处理的一句话总结就是操作intercept方法返回的next.handle(req),使用rxjs的map操作符进行映射。

详解使用angular的HttpClient搭配rxjs

四、搭配rxjs

rxjs是angular严重依赖的一个大坑,初次接触会被其创建和订阅这种使用方式搭配一大堆眼花缭乱的操作符弄得一脸懵逼。

创建-订阅的请求方式

原Http和新的HttpClient两个服务流严重依赖了rxjs,请求的发起返回的是一个Observable对象,其定义好后并不会直接发起请求,真正发起请求是在执行其subscribe方法的时候,此方法接收三个参数,分别是成功回调、失败回调和完成回调。

Promise的套路是请求在定义(调用)的时候就发起了,然后迎来的是一连串的then()和catch()。可以从catch中resolve到then,或者从then中reject到catch。

rxjs的套路则是先创建出一个观察者对象(Observable),可以用许多操作符定义许多规则,比如个人感觉很接近then的map操作符,以及接近catch的catch操作符。可以从map操作符中直接throw到错误回调,或者在catch操作符中捕捉错误并返回新的成功的流。这一切都不会触发这个请求,只有最终subscribe()的时候,才会真正执行整个请求,并在三种回调中体现。

详解使用angular的HttpClient搭配rxjs

对于rxjs的学习强烈推荐 Rxjs 5 ultimate 简直胜看十篇博。

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

Javascript 相关文章推荐
Javascript的IE和Firefox兼容性汇编(zz)
Feb 02 Javascript
jQuery操作Select选择的Text和Value(获取/设置/添加/删除)
Mar 06 Javascript
windows8.1+iis8.5下安装node.js开发环境
Dec 12 Javascript
jquery模拟进度条实现方法
Aug 03 Javascript
js简单倒计时实现代码
Apr 30 Javascript
9个让JavaScript调试更简单的Console命令
Nov 14 Javascript
Vue自定义指令介绍(2)
Dec 08 Javascript
详解有关easyUI的拖动操作中droppable,draggable用法例子
Jun 03 Javascript
js异步编程小技巧详解
Aug 14 Javascript
微信小程序methods中定义的方法互相调用的实例代码
Aug 07 Javascript
Javascript格式化并高亮xml字符串的方法及注意事项
Aug 13 Javascript
js+canvas实现转盘效果(两个版本)
Sep 13 Javascript
JS中关于正则的巧妙操作
Aug 31 #Javascript
JavaScript表单即时验证 验证不成功不能提交
Aug 31 #Javascript
js实现canvas保存图片为png格式并下载到本地的方法
Aug 31 #Javascript
js实现canvas图片与img图片的相互转换的示例
Aug 31 #Javascript
vue实现全选和反选功能
Aug 31 #Javascript
浅谈Vue 初始化性能优化
Aug 31 #Javascript
Vue keep-alive实践总结(推荐)
Aug 31 #Javascript
You might like
怎样给PHP源代码加密?PHP二进制加密与解密的解决办法
2013/04/22 PHP
php中3种方法删除字符串中间的空格
2014/03/10 PHP
PHP生成迅雷、快车、旋风等软件的下载链接代码实例
2014/05/12 PHP
Linux下创建nginx脚本-start、stop、reload…
2014/08/03 PHP
php计算两个整数的最大公约数常用算法小结
2015/03/05 PHP
如何在centos8自定义目录安装php7.3
2019/11/28 PHP
IE的有条件注释判定IE版本详解(附实例代码)
2012/01/04 Javascript
jquery的ajaxSubmit()异步上传图片并保存表单数据演示代码
2013/06/04 Javascript
jquery实现简单易懂的图片展示小例子
2013/11/21 Javascript
在jquery中combobox多选的不兼容问题总结
2013/12/24 Javascript
Javascript中的回调函数和匿名函数的回调示例介绍
2014/05/12 Javascript
document.forms用法示例介绍
2014/06/26 Javascript
JS实现的车标图片提示效果代码
2015/10/10 Javascript
Bootstrap基本样式学习笔记之标签(5)
2016/12/07 Javascript
js实现文字列表无缝滚动效果
2017/06/23 Javascript
Javascript 严格模式use strict详解
2017/09/16 Javascript
vuejs实现本地数据的筛选分页功能思路详解
2017/11/15 Javascript
swiper移动端轮播插件(触碰图片之后停止轮播)
2017/12/28 Javascript
详解vue组件基础
2018/05/04 Javascript
如何优雅的在一台vps(云主机)上面部署vue+mongodb+express项目
2019/01/20 Javascript
Vue安装浏览器开发工具的步骤详解
2019/05/12 Javascript
Vue 使用beforeEach实现登录状态检查功能
2019/10/31 Javascript
python批量生成本地ip地址的方法
2015/03/23 Python
Android分包MultiDex策略详解
2017/10/30 Python
Python flask路由间传递变量实例详解
2020/06/03 Python
详解python3 GUI刷屏器(附源码)
2021/02/18 Python
CSS3 实现弹幕的示例代码
2017/08/07 HTML / CSS
CSS3 实现发光边框特效
2020/11/11 HTML / CSS
家教广告词
2014/03/19 职场文书
公司董事长岗位职责
2014/06/08 职场文书
上海世博会口号
2014/06/19 职场文书
社区爱国卫生月活动总结
2014/06/30 职场文书
老公保证书怎么写
2015/02/26 职场文书
教师外出学习心得体会
2016/01/18 职场文书
详解Java实现设计模式之责任链模式
2021/06/23 Java/Android
能让Python提速超40倍的神器Cython详解
2021/06/24 Python