【Angular中的HTTP请求】- 拦截器 HttpInterceptor 详解
通过学习 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 详解相关推荐
- dio拦截器 flutter_详解flutter之网络请求dio,请求,拦截器简单示例
flutter一直很火的网络请求插件dio 直接上代码,写成一个类,可以直接使用 包含请求的封装,拦截器的封装 import 'package:dio/dio.dart'; import 'dart: ...
- Spring MVC 拦截器 interceptor 详解
Spring MVC-拦截器 今天就是把有关拦截器的知识做一个总结. 1.拦截器概述 1.1 什么是拦截器? Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(F ...
- Spring Boot拦截器(Interceptor)详解
写了那么久的博客,始于Python爬虫,目前专于Java学习,终于有了属于自己的小窝,欢迎各位访问我的个人网站. 文章目录 Interceptor 介绍 Interceptor 作用 自定义 Inte ...
- Spring拦截器配置详解(如何定义一个拦截器)
一.前言 Spring和SpringBoot的拦截器也是对请求进行的系列验证或处理,关于拦截器和过滤器的区别此文不做介绍,之前我看到过一篇相关系列的文章,讲述的还比较详细,给大家参考参考:拦截器与过滤 ...
- php request对象,PHP 中TP5 Request 请求对象的实例详解
PHP 中TP5 Request 请求对象 public/index.php app\index\controller\Index.php <?php namespace app\index\c ...
- vue中的请求拦截器与响应拦截器的使用
之前讲到在项目中封装了axios,vue中对axios封装 就有了request.js这个文件,那么在这个文件中就可以写请求拦截器与响应拦截器. 请求拦截器: 请求拦截器的作用是在请求发送前进行一些操 ...
- vue项目中 axios请求拦截器与取消pending请求功能 - 年少、 - 博客园
在开发vue项目中,请求是不可缺少的,在发送请求时常常需要统一处理一些请求头参数等设置与响应事件,这时利用请求拦截器再好不过. 这里以axios请求为例 实现了设置统一请求头添加token, 其中to ...
- axios请求拦截器错误_React中使用高阶组件和axios的拦截器,统一处理请求失败提示...
在前端开发中,判断边界条件和重要,通常我们要花费开发中的很大一部分时间做边界条件处理.发送ajax请求时,假设有这样一个需求: 每个页面发送ajax请求,如果请求失败,在页面上统一弹出样式一样的错误提 ...
- 如何使用 Axios 中的请求拦截器 和响应拦截器
Axios 是一个常用的 JavaScript 库,用于发送 HTTP 请求和处理响应.在网站设计中,我们可以使用 Axios 请求拦截器和响应拦截器来实现一些常见的需求,例如添加认证信息.处理错误信 ...
最新文章
- python如何读取数据集_如何在Python中读取通用数据格式(CDF)
- adxl276怎么添加到proteus中_奶粉中的营养强化剂和食品添加剂是怎么一回事?
- sentinel 端口_Sentinel原理:控制台是如何获取到实时数据的
- 面试经历-19-03-14
- 计算机软件等级认证,中国计算机学会推出软件非专业级别能力认证
- ionic 富文本编辑样式后,前台不能回显样式
- 转android项目开发 工作日志 2011.10.8--toast消息框使用
- 在两个林间做Exchange邮箱的迁移
- 网站导航(URL 映射和路由)
- (附源码)app订餐APP 毕业设计 190711
- PDF虚拟打印机的功能详解和使用方法
- dlib实现人脸对齐方法
- flink 容错机制(检查点的保存、恢复、检查点算法、保存点、状态一致性的三种级别、end-to-end exactly-once)
- 同时掌握96门语言,取得多项世界突破,百度发布预训练模型ERNIE-M
- 日本語 IME输入法(Microsoft 输入法)切换问题
- 神经网络的心得体会,神经网络心得体会
- (转)东方美人吉他谱及演奏(中川砂仁)
- WiFi以及WLAN技术介绍
- 电脑蓝屏---错误代码:0xc0000185,修复过程转0xc0000001,最后成功修复
- c++计算数组的中值
热门文章
- C++读取和写入文件 Mark !! 汉字转拼音 带声调!
- 向量的方向余弦公式_方向余弦
- 广发计算机首席研究员,2012年新财富行问业最佳分析师资料库.doc
- java 答题卡_阅读以下说明和java代码,将应填入(n)处的字句写在答题纸的对应栏内。【说明】 - 信管网...
- word中整理疏忽的页眉页脚操作
- 专业分析室内装修墙面集成板好还是墙砖好
- 几个GALGAME 注册表补丁
- Java中上传图片和下载图片
- java 爬虫 抓取网上的图片报错521解决方案
- 纯英文,数字不换行问题处理