通过学习 HttpClient 的工作机制 ,我们知道对于HTTP请求,HttpClient 实际上是构建了一个链式的处理流程:

在HttpBackend的处理流程中请求被发出。在HttpBackend的前面可以设置多个的拦截器,对请求进行处理。

HttpClient 的详细说明请参考:Angular 中的 HttpClient 请求详解

1、编写拦截器

要实现拦截器,就要实现一个实现了 HttpInterceptor 接口中的 intercept() 方法的类。

以下代码实现一个除了添加打印外,不做其他处理的拦截器:

import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent } from '@angular/common/http'
import { Observable } from "rxjs";
import { mergeMap } from "rxjs/operators";@Injectable()
export class InterceptorA implements HttpInterceptor {intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {req = this.handleRequest(req);return next.handle(req).pipe(mergeMap(evt => this.handleResponse(evt)));}/*** 请求参数拦截处理*/handleRequest(req: any) {console.log(`拦截器A在请求发起前的拦截处理`);return req;}/*** 返回结果拦截处理*/handleResponse(evt: any) {console.log("拦截器A在数据返回后的拦截处理");return new Observable<HttpEvent<any>>(observer => {observer.next(evt);});}
}

实际项目中,可以根据需求在上述 handleRequest() 方法 和 handleResponse() 方法中添加想要的拦截处理逻辑。

intercept() 方法中的 next 对象表示拦截器链表中的下一个拦截器,通过调用 next.handle() 达成链式调用效果。这个链表中的最后一个 next 对象就是 HttpClient 的后端处理器(HttpBackend),它会把请求发给服务器,并接收服务器的响应。

2、注册提供拦截器

这个 InterceptorA 就是一个由 Angular 依赖注入(DI)系统管理的服务。 像其它服务一样,你也必须先提供这个拦截器类,程序才能使用它。

由于拦截器是 HttpClient 服务的可选依赖,所以你必须在提供 HttpClient 的同一个(或其各级父注入器)注入器中注册提供这些拦截器。由于在 AppModule 中导入了 HttpClientModule,因此本应用在其根注入器中提供了 HttpClient。所以同样要在 AppModule 中注册提供这些拦截器。

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { InterceptorA } from './core/kits/interceptor-a';@NgModule({declarations: [AppComponent],imports: [BrowserModule,HttpClientModule,AppRoutingModule],providers: [{ provide: HTTP_INTERCEPTORS, useClass: InterceptorA, multi: true }],   // InterceptorA 注册语句bootstrap: [AppComponent]
})
export class AppModule { }

注意 multi: true 选项。 这个必须的选项会告诉 Angular HTTP_INTERCEPTORS 是一个多重提供者的令牌,表示它会注入一个多值的数组,而不是单一的值。

3、拦截器效果

在组件中调用HttpClient get() 方法,以CSDN 获取热门搜索关键词列表为例:

    let url = `https://silkroad.csdn.net/api/v2/assemble/list/channel/search_hot_word?channel_name=pc_hot_word&size=10&platform=pc`;console.log(`组件调用请求方法`);this.http.get(url).subscribe(data => {console.log("组件拿到请求返回数据");});

调试程序,页面打印如下:

通过打印发现在数据返回后的拦截处理被触发了两次。这是因为正常情况下 HttpBackend 的处理过程中向外发出了两次数据通知。

一次是发送请求后立即发出了请求发出状态的通知:

这里发出的数据是 { type: 0 } 。

( 跟踪代码定义可以知道 HttpEventType[HttpEventType["Sent"] = 0] )

另一次是在 XMLHttpRequest 的 onLoad 事件中:

这里发出的数据是一个 HttpResponse 对象 。

根据两次发出的值,调整拦截器 InterceptorA 代码对发送状态和返回数据进行区分处理:

    /*** 返回结果拦截处理*/handleResponse(evt: any) {return new Observable<HttpEvent<any>>(observer => {if (evt instanceof HttpResponse) {console.log("拦截器A在数据返回后的拦截处理");} else {console.log(`拦截器A接收到请求发出状态:${JSON.stringify(evt)}`);}observer.next(evt);});}

调整后的拦截打印如下图所示:

4、多个拦截器

按照上诉流程再添加一个拦截器B,查看拦截效果。

在 AppModule 中添加 InterceptorB 的注册语句:

  providers: [{ provide: HTTP_INTERCEPTORS, useClass: InterceptorA, multi: true },{ provide: HTTP_INTERCEPTORS, useClass: InterceptorB, multi: true },],

调试运行,页面打印如下:

可以看出,排序靠后的拦截器在请求发出前会靠后进行请求参数的拦截处理,在处理请求返回值时,排序靠后的拦截器会优先对返回数据进行拦截处理。所有拦截器都处理完成后组件才拿到返回数据。

5、返回数据过滤

通过打印信息还可以发现,拦截器都捕获了请求的发出状态信息。但是组件里边并没有拿到,组件里只获取到了返回数据。

这是因为 HttpClient 在 HttpHandler 处理后又对数据作了过滤处理,只能返回 HttpResponse 信息:

6、默认拦截器

细心的同学经过断点就可以发现在实际程序中,存在的拦截器比自己注册的多了一个 (HttpXsrfInterceptor) :

查看代码可以发现,HttpXsrfInterceptor 是在 HttpClientXsrfModule 中注册:

然后 HttpClientModule 引入了 HttpClientXsrfModule :

因为AppModule中就引入了HttpClientModule 所以程序中实际上默认就启用了拦截器 HttpXsrfInterceptor 。

查看 HttpXsrfInterceptor 定义:

/*** `HttpInterceptor` which adds an XSRF token to eligible outgoing requests.*/
class HttpXsrfInterceptor {constructor(tokenService, headerName) {this.tokenService = tokenService;this.headerName = headerName;}intercept(req, next) {const lcUrl = req.url.toLowerCase();// Skip both non-mutating requests and absolute URLs.// Non-mutating requests don't require a token, and absolute URLs require special handling// anyway as the cookie set// on our origin is not the same as the token expected by another origin.if (req.method === 'GET' || req.method === 'HEAD' || lcUrl.startsWith('http://') ||lcUrl.startsWith('https://')) {return next.handle(req);}const token = this.tokenService.getToken();// Be careful not to overwrite an existing header of the same name.if (token !== null && !req.headers.has(this.headerName)) {req = req.clone({ headers: req.headers.set(this.headerName, token) });}return next.handle(req);}
}

注释说明,HttpInterceptor向符合条件的传出请求添加XSRF令牌。这里符合条件的请求指非变异请求和绝对URL(non-mutating requests and absolute URLs)。从代码中看来指同源的非GET和HEAD的请求。

【Angular中的HTTP请求】- 拦截器 HttpInterceptor 详解相关推荐

  1. dio拦截器 flutter_详解flutter之网络请求dio,请求,拦截器简单示例

    flutter一直很火的网络请求插件dio 直接上代码,写成一个类,可以直接使用 包含请求的封装,拦截器的封装 import 'package:dio/dio.dart'; import 'dart: ...

  2. Spring MVC 拦截器 interceptor 详解

    Spring MVC-拦截器 今天就是把有关拦截器的知识做一个总结. 1.拦截器概述 1.1 什么是拦截器? Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(F ...

  3. Spring Boot拦截器(Interceptor)详解

    写了那么久的博客,始于Python爬虫,目前专于Java学习,终于有了属于自己的小窝,欢迎各位访问我的个人网站. 文章目录 Interceptor 介绍 Interceptor 作用 自定义 Inte ...

  4. Spring拦截器配置详解(如何定义一个拦截器)

    一.前言 Spring和SpringBoot的拦截器也是对请求进行的系列验证或处理,关于拦截器和过滤器的区别此文不做介绍,之前我看到过一篇相关系列的文章,讲述的还比较详细,给大家参考参考:拦截器与过滤 ...

  5. php request对象,PHP 中TP5 Request 请求对象的实例详解

    PHP 中TP5 Request 请求对象 public/index.php app\index\controller\Index.php <?php namespace app\index\c ...

  6. vue中的请求拦截器与响应拦截器的使用

    之前讲到在项目中封装了axios,vue中对axios封装 就有了request.js这个文件,那么在这个文件中就可以写请求拦截器与响应拦截器. 请求拦截器: 请求拦截器的作用是在请求发送前进行一些操 ...

  7. vue项目中 axios请求拦截器与取消pending请求功能 - 年少、 - 博客园

    在开发vue项目中,请求是不可缺少的,在发送请求时常常需要统一处理一些请求头参数等设置与响应事件,这时利用请求拦截器再好不过. 这里以axios请求为例 实现了设置统一请求头添加token, 其中to ...

  8. axios请求拦截器错误_React中使用高阶组件和axios的拦截器,统一处理请求失败提示...

    在前端开发中,判断边界条件和重要,通常我们要花费开发中的很大一部分时间做边界条件处理.发送ajax请求时,假设有这样一个需求: 每个页面发送ajax请求,如果请求失败,在页面上统一弹出样式一样的错误提 ...

  9. 如何使用 Axios 中的请求拦截器 和响应拦截器

    Axios 是一个常用的 JavaScript 库,用于发送 HTTP 请求和处理响应.在网站设计中,我们可以使用 Axios 请求拦截器和响应拦截器来实现一些常见的需求,例如添加认证信息.处理错误信 ...

最新文章

  1. python如何读取数据集_如何在Python中读取通用数据格式(CDF)
  2. adxl276怎么添加到proteus中_奶粉中的营养强化剂和食品添加剂是怎么一回事?
  3. sentinel 端口_Sentinel原理:控制台是如何获取到实时数据的
  4. 面试经历-19-03-14
  5. 计算机软件等级认证,中国计算机学会推出软件非专业级别能力认证
  6. ionic 富文本编辑样式后,前台不能回显样式
  7. 转android项目开发 工作日志 2011.10.8--toast消息框使用
  8. 在两个林间做Exchange邮箱的迁移
  9. 网站导航(URL 映射和路由)
  10. (附源码)app订餐APP 毕业设计 190711
  11. PDF虚拟打印机的功能详解和使用方法
  12. dlib实现人脸对齐方法
  13. flink 容错机制(检查点的保存、恢复、检查点算法、保存点、状态一致性的三种级别、end-to-end exactly-once)
  14. 同时掌握96门语言,取得多项世界突破,百度发布预训练模型ERNIE-M
  15. 日本語 IME输入法(Microsoft 输入法)切换问题
  16. 神经网络的心得体会,神经网络心得体会
  17. (转)东方美人吉他谱及演奏(中川砂仁)
  18. WiFi以及WLAN技术介绍
  19. 电脑蓝屏---错误代码:0xc0000185,修复过程转0xc0000001,最后成功修复
  20. c++计算数组的中值

热门文章

  1. C++读取和写入文件 Mark !! 汉字转拼音 带声调!
  2. 向量的方向余弦公式_方向余弦
  3. 广发计算机首席研究员,2012年新财富行问业最佳分析师资料库.doc
  4. java 答题卡_阅读以下说明和java代码,将应填入(n)处的字句写在答题纸的对应栏内。【说明】 - 信管网...
  5. word中整理疏忽的页眉页脚操作
  6. 专业分析室内装修墙面集成板好还是墙砖好
  7. 几个GALGAME 注册表补丁
  8. Java中上传图片和下载图片
  9. java 爬虫 抓取网上的图片报错521解决方案
  10. 纯英文,数字不换行问题处理