首页 > 其他分享 >Angular中的HTTP请求】- 拦截器 HttpInterceptor 详解

Angular中的HTTP请求】- 拦截器 HttpInterceptor 详解

时间:2023-06-13 15:12:32浏览次数:42  
标签:拦截器 HTTP 请求 req next import Angular HttpClient

原文: 【Angular中的HTTP请求】- 拦截器 HttpInterceptor 详解__老杨_的博客-CSDN博客

通过学习 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 的 onl oad 事件中:

 

这里发出的数据是一个 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的请求。
————————————————
版权声明:本文为CSDN博主「_老杨_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/evanyanglibo/article/details/122368884

标签:拦截器,HTTP,请求,req,next,import,Angular,HttpClient
From: https://www.cnblogs.com/bruce1992/p/17477556.html

相关文章

  • window下安装docker并运行angular项目
    window下安装docker并运行angular项目1、使用场景本地有一个node项目,node版本是v16.13.2,在本地安装的angular是15.2.4但是测试服上面的node版本是14.19.3,angular是1.0.0-beta.28.3,会导致angular项目的ngbuild打包不了。但是不能升级版本,因为这个测试服务器上面的东西也......
  • 选择http代理IP需要考虑哪些因素
    对于爬虫工作者来说,选择合适的代理IP是很重要的一项工作,正所谓“工欲善其事必先利其器”。那么选择http代理IP需要考虑哪些因素呢?1、价格很多人选择代理IP首先看重的就是价格,货比三家也只比价格,不可否认,价格确实很重要。毕竟公司是有预算限制的,但需要在质量相差不多的情况下,选择价......
  • ABAP 调用HTTP上传附件(二)之中文乱码
    1、这篇文章的由来之前已经发表了《ABAP调用HTTP上传附件》的文章,详细介绍了如何通过HTTP请求传输附件,可点击链接参考原有文档因为之前对传输文件的中文文件名处理上解释不够详细,也因为不够重视,导致又一次在相关问题上踩坑。而浪费一天时间的问题,最终原因竟然就是个这?哭笑不得!目瞪......
  • window下安装docker并运行angular项目
    window下安装docker并运行angular项目1、使用场景本地有一个node项目,node版本是v16.13.2,在本地安装的angular是15.2.4但是测试服上面的node版本是14.19.3,angular是1.0.0-beta.28.3,会导致angular项目的ngbuild打包不了。但是不能升级版本,因为这个测试服务器上面的东西也......
  • 什么是HLS(HTTP Live Streaming)?
    HLSEasyTech#013#2009年,Apple推出了HLS(HTTPLiveStreaming)——基于HTTP的自适应码率流媒体传输协议。HLS描述了一组通过互联网提供音视频服务的工具和程序。一个视频可以被分割成多个视频切片,这些切片的传送位置和顺序在一组被称为播放列表的XML文件中,该文件以文件扩展名m3u8结尾......
  • HTTP/3特性分析及未来发展
    Robin讲HTTP/3#005#到现在为止,我们主要对比了QUIC和TCP中的性能特性。那么HTTP/3和HTTP/2之间的区别是什么?我们在第一部分讨论过,HTTP/3实际上是HTTP/2-over-QUIC,所以新版本中并没有推出什么真正重要的新特性。这与从HTTP/1到HTTP/2不同,其中的变化更多,并推出了如头压缩、流优先级和......
  • 使用RestTemplate发送http请求导致请求头被过滤
    问题描述:  服务内需要使用http请求访问第三方接口,由于安全问题,第三方接口为防止跨域问题,在Nginx增加了请求头(Host,Origin,Refere)判断规则,判断不通过便返回404。一次调用过程,确保请求地址,请求头,参数均没问题后,却一直404。 原因:  RestTemplate中默认使用的connector会......
  • 计算机网络协议之http协议(四)
    一、HTTP协议概述HTTP协议又称超文本传输协议,是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。HTTP协议的特点如下:基于客户/服务器模式。在HTTP/0.9和1.0中每次连接只处理一个请求。服务器不保留与客......
  • QT的http post
    QT+=network#ifndefMAINWINDOW_H#defineMAINWINDOW_H#include<QMainWindow>#include<QWidget>#include<QObject>#include<QDebug>#include<QHttpMultiPart>#include<QNetworkAccessManager>#include<QNetw......
  • python使用HTTP隧道代理代码示例模板
    以下是使用HTTP隧道代理的Python代码示例模板:```pythonimportrequests#设置代理服务器地址和端口号proxy_host="your_proxy_host"proxy_port="your_proxy_port"#设置代理服务器的用户名和密码(如果需要)proxy_username="your_proxy_username"proxy_password="your_proxy_p......