详解使用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 相关文章推荐
动态表格Table类的实现
Aug 26 Javascript
Js setInterval与setTimeout(定时执行与循环执行)的代码(可以传入参数)
Jun 11 Javascript
capacityFixed 基于jquery的类似于新浪微博新消息提示的定位框
May 24 Javascript
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
May 23 Javascript
javascripit实现密码强度检测代码分享
Dec 12 Javascript
JavaScript 实现的 zip 压缩和解压缩工具包Zip.js使用详解
Dec 14 Javascript
AngularJS过滤器详解及示例代码
Aug 16 Javascript
jQuery中JSONP的两种实现方式详解
Sep 26 Javascript
highCharts提示框中显示当前时间的方法
Jan 18 Javascript
如何对react hooks进行单元测试的方法
Aug 14 Javascript
Layui数据表格 前后端json数据接收的方法
Sep 19 Javascript
使用refresh_token实现无感刷新页面
Apr 26 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 Ajax实现页面无刷新发表评论
2007/01/02 PHP
PHP中copy on write写时复制机制介绍
2014/05/13 PHP
php使用gd2绘制基本图形示例(直线、圆、正方形)
2017/02/15 PHP
PHP文件上传小程序 适合初学者学习!
2019/05/23 PHP
在thinkphp5.0路径中实现去除index.php的方式
2019/10/16 PHP
php正则表达式使用方法整理集合
2020/01/31 PHP
js判断变量是否空值的代码
2008/10/26 Javascript
cloudgamer出品ImageZoom 图片放大效果
2010/04/01 Javascript
用js来刷新当前页面保留参数的具体实现
2013/12/23 Javascript
JQuery动画animate的stop方法使用详解
2014/05/09 Javascript
js超时调用setTimeout和间歇调用setInterval实例分析
2015/01/28 Javascript
基于jquery实现动态竖向柱状条特效
2016/02/12 Javascript
谈谈JavaScript中浏览器兼容问题的写法小议
2016/12/17 Javascript
JS前端开发判断是否是手机端并跳转操作(小结)
2017/02/05 Javascript
Vuex简单入门
2017/04/19 Javascript
使用vue制作FullPage页面滚动效果
2017/08/21 Javascript
node.js自动上传ftp的脚本分享
2018/06/16 Javascript
vue通过video.js解决m3u8视频播放格式的方法
2019/07/30 Javascript
React学习之受控组件与数据共享实例分析
2020/01/06 Javascript
解决vue prop传值default属性如何使用,为何不生效的问题
2020/09/21 Javascript
简单了解Python下用于监视文件系统的pyinotify包
2015/11/13 Python
讲解Python的Scrapy爬虫框架使用代理进行采集的方法
2016/02/18 Python
python3实现抓取网页资源的 N 种方法
2017/05/02 Python
对python制作自己的数据集实例讲解
2018/12/12 Python
Python3最长回文子串算法示例
2019/03/04 Python
python实现计数排序与桶排序实例代码
2019/03/28 Python
基于python+selenium的二次封装的实现
2020/01/06 Python
Python PyQt5运行程序把输出信息展示到GUI图形界面上
2020/04/27 Python
django rest framework使用django-filter用法
2020/07/15 Python
Coggles美国/加拿大:高级国际时装零售商
2018/10/23 全球购物
用C#语言写出与SQLSERVER访问时的具体过程
2013/04/16 面试题
股份合作协议书范本
2014/04/14 职场文书
市政工程技术专业自荐书
2014/07/06 职场文书
仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案
2021/05/06 MySQL
一文彻底理解js原生语法prototype,__proto__和constructor
2021/10/24 Javascript
使用 Docker Compose 构建复杂的多容器App
2022/04/30 Servers