【Angular中的HTTP请求】- HttpClient 详解

这篇具有很好参考价值的文章主要介绍了【Angular中的HTTP请求】- HttpClient 详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        大多数前端应用都要通过 HTTP 协议与服务器通讯,才能下载或上传数据并访问其它后端服务。Angular 给应用提供了一个 HTTP 客户端 API,也就是 @angular/common/http 中的 HttpClient 服务类。

1、HttpClient的使用

        要想使用 HttpClient,就要先导入 Angular 的 HttpClientModule。一般都是在根模块 AppModule 中进行导入。

        app/app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    BrowserModule,

    HttpClientModule,
    // ... other modules ...
  ],
  declarations: [
    AppComponent,
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {}

        然后把 HttpClient 服务注入成一个服务类的依赖项,在服务类的方法中进行使用:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ApiService {
  constructor(private http: HttpClient) { }
  
   getUserList(){
       const url = "/api/user/list";
       return this.http.get<any>(url);   
   }
}

        然后在组件中调用服务获取数据进行处理:

import { Component } from '@angular/core';
import { ApiService } from '../services/api.service';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent {
    
   userList:Array<any> = []; 
   constructor(private api: ApiService) { }
   
   getUserList(){
       this.api. getUserList.subscribe(data=>{
           this.userList = data;       
       });
   }
}

2、常用请求方法

        HttpClient 类包含了 get post delete put 等常见的 HTTP 请求方法。主要的方法声明如下:

    get<T>(url: string, options?: {
        headers?: HttpHeaders | { [header: string]: string | string[]; };
        observe?: 'body';
        params?: HttpParams | { [param: string]: string | string[]; };
        reportProgress?: boolean;
        responseType?: 'json';
        withCredentials?: boolean;
    }): Observable<T>;
    
    post<T>(url: string, body: any | null, options: {
        headers?: HttpHeaders | { [header: string]: string | string[]; };
        observe: 'response';
        params?: HttpParams | { [param: string]: string | string[]; };
        reportProgress?: boolean;
        responseType?: 'json';
        withCredentials?: boolean;
    }): Observable<HttpResponse<T>>;
    
    delete<T>(url: string, options?: {
        headers?: HttpHeaders | { [header: string]: string | string[]; };
        observe?: 'body';
        params?: HttpParams | { [param: string]: string | string[]; };
        reportProgress?: boolean;
        responseType?: 'json';
        withCredentials?: boolean;
    }): Observable<T>;
    
    put<T>(url: string, body: any | null, options?: {
        headers?: HttpHeaders | { [header: string]: string | string[]; };
        observe?: 'body';
        params?: HttpParams | { [param: string]: string | string[]; };
        reportProgress?: boolean;
        responseType?: 'json';
        withCredentials?: boolean;
    }): Observable<T>;

        这里只主要列举了四个常用的方法,实际上还有 request, head, options, patch, jsonp 等方法,并且相同的方法名也存在多个重载方法。项目中可以根据实际需求调用合适的方法。

        可以看到所有请求的方法返回值都是 Observable 可观察对象。

3、调用关系

        查阅 HttpClient 类的源代码,可以发现全部的请求方法都是通过传递不同参数来调用 request方法:

    get(url, options = {}) {
        return this.request('GET', url, (/** @type {?} */ (options)));
    }
    
    post(url, body, options = {}) {
        return this.request('POST', url, addBody(options, body));
    }    
    
    delete(url, options = {}) {
        return this.request('DELETE', url, (/** @type {?} */ (options)));
    }    
    
    put(url, body, options = {}) {
        return this.request('PUT', url, addBody(options, body));
    }   

        request 方法关键代码如下:

    // Start with an Observable.of() the initial request, and run the handler (which
    // includes all interceptors) inside a concatMap(). This way, the handler runs
    // inside an Observable chain, which causes interceptors to be re-run on every
    // subscription (this also makes retries re-run the handler, including interceptors).
    /** @type {?} */
    const events$ = of (req).pipe(concatMap((req) => this.handler.handle(req)));
    ......
    // The requested stream contains either the full response or the body. In either
    // case, the first step is to filter the event stream to extract a stream of
    // responses(s).
    /** @type {?} */
    const res$ = ( /** @type {?} */ (events$.pipe(filter((event) => event instanceof HttpResponse))));
    ......

        可以看到主要的步骤包括:

        1、of (req) : 使用 RxJS 的 of 操作符基于请求信息新建的一个单播的 Cold Observable (数据流,原始的数据就是请求信息) 。

        2、pipe(concatMap((req) => this.handler.handle(req))) 经过 concatMap 操作符对数据流进行处理。处理的方法就是 (req) => this.handler.handle(req);实际的请求的发送就是在this.handler.handle(req)方法中。

        3、events$.pipe(filter((event) => event instanceof HttpResponse)) 过滤数据流中的 HttpResponse 数据。

        完成以上步骤后,request 方法返回操作符处理后的 Observable。因为返回的是 单播的 Cold Observable,所以只有在 subscribe 的时候才会开启 Observable 的数据通知;发出数据通知后才会调用 concatMap 中的处理方法,才会发起实际的HTTP请求。所以只有在 Observable.subscribe() 方法执行的时候,浏览器才会发起HTTP请求。

4、handle() 方法跟踪

        上文已指出实际的请求是在 this.handler.handle(req) 方法中完成的,实际上在 handle() 方法中不仅只是发起请求。

        查看代码找到 this.handler 定义,先看声明:

export declare class HttpClient {
    private handler;
    constructor(handler: HttpHandler);
    ...
}

        再看源代码:

class HttpClient {
    constructor(handler) {
        this.handler = handler;
    }
    ...
}

        可以发现 this.handler 为一个 HttpHandler 对象。

        查看声明可以发现 HttpHandler 是一个抽象类:

/**
 * Transforms an `HttpRequest` into a stream of `HttpEvent`s, one of which will likely be a
 * `HttpResponse`.
 *
 * `HttpHandler` is injectable. When injected, the handler instance dispatches requests to the
 * first interceptor in the chain, which dispatches to the second, etc, eventually reaching the
 * `HttpBackend`.
 *
 * In an `HttpInterceptor`, the `HttpHandler` parameter is the next interceptor in the chain.
 *
 * @publicApi
 */
export declare abstract class HttpHandler {
    abstract handle(req: HttpRequest<any>): Observable<HttpEvent<any>>;
}

        百度翻译一下注释:将一个 “Http 请求” 转换为 “HttpEvent” 事件流,事件流中可能就存在“HttpResponse”。HttpHandler 是可注入的。 注入时,处理程序实例将请求分派到链中的第一个拦截器,然后分派到第二个拦截器,第三个拦截器,依次分派,最终到达 HttpBackend。在 HttpInterceptor 中,HttpHandler 参数是链中的下一个拦截器。

        通过注释可以发现 HttpHandler 通过 handle() 方法对请求进行了一个链式的处理流程:主要包括不定数量的拦截器的处理加上最后的 HttpBackend 的处理。

【Angular中的HTTP请求】- HttpClient 详解

         查看代码,找到 HttpHandler 的实现类:

/**
 * An injectable `HttpHandler` that applies multiple interceptors
 * to a request before passing it to the given `HttpBackend`.
 *
 * The interceptors are loaded lazily from the injector, to allow
 * interceptors to themselves inject classes depending indirectly
 * on `HttpInterceptingHandler` itself.
 * @see `HttpInterceptor`
 */
export declare class ɵHttpInterceptingHandler implements HttpHandler {
    private backend;
    private injector;
    private chain;
    constructor(backend: HttpBackend, injector: Injector);
    handle(req: HttpRequest<any>): Observable<HttpEvent<any>>;
}

        百度翻译一下注释:一个可注入的 HttpHandler,在将请求传递给给定的 HttpBackend 之前,将多个拦截器应用于请求。拦截器从注入器延迟加载,以允许拦截器自己注入类,这间接依赖于 HttpInterceptingHandler 本身。

        查看源代码,发现 ɵHttpInterceptingHandler 只是 HttpInterceptingHandler 的别名:

export {
    ... 
    HttpBackend, HttpHandler, HttpClient, HttpHeaders, 
    HTTP_INTERCEPTORS, JsonpClientBackend, JsonpInterceptor, 
    ... 
    HttpInterceptingHandler as ɵHttpInterceptingHandler,
    ... 
};

        找到 HttpInterceptingHandler 的源代码:

class HttpInterceptingHandler {
    /**
     * @param {?} backend
     * @param {?} injector
     */
    constructor(backend, injector) {
        this.backend = backend;
        this.injector = injector;
        this.chain = null;
    }
    /**
     * @param {?} req
     * @return {?}
     */
    handle(req) {
        if (this.chain === null) {
            /** @type {?} */
            const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
            this.chain = interceptors.reduceRight((/**
             * @param {?} next
             * @param {?} interceptor
             * @return {?}
             */
            (next, interceptor) => new HttpInterceptorHandler(next, interceptor)), this.backend);
        }
        return this.chain.handle(req);
    }
}

        从handle() 方法的代码中可以看出,的确如上述注释描述的那样:

        通过 const interceptors = this.injector.get(HTTP_INTERCEPTORS, []); 获取模块中注册使用的拦截器。

        通过 reduceRight() 方法,将 拦截器和 HttpBackend 组成一个链式结构,对请求进行处理。

5、HttpBackend 介绍

        拦截器(HttpInterceptor)的介绍请参考:Angular请求拦截器HttpInterceptor详解

        这里直接看链式处理流程的最后一个环节,HttpBackend 的处理。先看 HttpBackend 的声明:

/**
 * A final `HttpHandler` which will dispatch the request via browser HTTP APIs to a backend.
 *
 * Interceptors sit between the `HttpClient` interface and the `HttpBackend`.
 *
 * When injected, `HttpBackend` dispatches requests directly to the backend, without going
 * through the interceptor chain.
 *
 * @publicApi
 */
export declare abstract class HttpBackend implements HttpHandler {
    abstract handle(req: HttpRequest<any>): Observable<HttpEvent<any>>;
}

        注释说明 HttpBackend 就是最终将请求通过浏览器HTTP API 发送到后端 的 处理程序。拦截器位于 HttpClientHttpBackend 之间,HttpBackend 直接发送请求到后端,不会再经过拦截器的链式处理流程。这里的注释进一步印证了前述的流程说明。

        HttpBackend 也是一个抽象类,查找 HttpBackend 的实现类,会发现有两个,一个是 HttpXhrBackend,另一个是 JsonpClientBackend, 通过代码注释可以知道 HttpXhrBackend 是使用 XMLHttpRequest 发送请求的,而 JsonpClientBackend 是使用 JSONP 方法发送请求的。

        而 HttpClientModule 中使用的是 HttpXhrBackend

【Angular中的HTTP请求】- HttpClient 详解

         我们看 HttpXhrBackend 的声明:

/**
 * Uses `XMLHttpRequest` to send requests to a backend server.
 * @see `HttpHandler`
 * @see `JsonpClientBackend`
 *
 * @publicApi
 */
export declare class HttpXhrBackend implements HttpBackend {
    private xhrFactory;
    constructor(xhrFactory: XhrFactory);
    /**
     * Processes a request and returns a stream of response events.
     * @param req The request object.
     * @returns An observable of the response events.
     */
    handle(req: HttpRequest<any>): Observable<HttpEvent<any>>;
}

        再看 HttpXhrBackend 的源代码:

      handle(req) {
        ......
        return new Observable((
        (observer) => {
            const xhr = this.xhrFactory.build();
            xhr.open(req.method, req.urlWithParams);
            ......
            const partialFromXhr = (() => { ... });
            const onLoad =  (() => { ... }); 
            const onError = ( (error) => { ... });
            const onDownProgress = ( (event) => {
             ... 
              observer.next(progressEvent);
             });
            const onUpProgress = ( (event) => {
             ... 
              observer.next(progressEvent);
             });
            xhr.addEventListener('load', onLoad);
            xhr.addEventListener('error', onError);
            if (req.reportProgress) {
                // Download progress is always enabled if requested.
                xhr.addEventListener('progress', onDownProgress);
                // Upload progress depends on whether there is a body to upload.
                if (reqBody !== null && xhr.upload) {
                    xhr.upload.addEventListener('progress', onUpProgress);
                }
            }
            // Fire the request, and notify the event stream that it was fired. 
            xhr.send((/** @type {?} */ (reqBody)));  // 实际发出请求的代码
            observer.next({ type: HttpEventType.Sent });
            
            return (
            () => {
                // On a cancellation, remove all registered event listeners.
                xhr.removeEventListener('error', onError);
                xhr.removeEventListener('load', onLoad);
                if (req.reportProgress) {
                    xhr.removeEventListener('progress', onDownProgress);
                    if (reqBody !== null && xhr.upload) {
                        xhr.upload.removeEventListener('progress', onUpProgress);
                    }
                }
                // Finally, abort the in-flight request.
                xhr.abort();
            });
        }));
    }

        其中  const xhr = this.xhrFactory.build();  xhrXMLHttpRequest,对应源代码:

/**
 * A factory for `HttpXhrBackend` that uses the `XMLHttpRequest` browser API.
 *
 */
class BrowserXhr {
    constructor() { }
    /**
     * @return {?}
     */
    build() { return (/** @type {?} */ ((new XMLHttpRequest()))); }
}

        使用 JSONP 方法发送请求时使用的 HttpBackendJsonpClientBackend,想要使用JSONP 发送请求需要导入 HttpClientJsonpModule,请参考:【Angular中的HTTP请求】- JSONP 详解 

6、总结       

        综上, HttpClient 就是集成了 RxJS 和 XMLHttpRequest 的封装;所有的请求都是通过 HttpClient.request() 进行调用,方法返回 Cold Observable, 在 Observable 被订阅的时候,请求先经过拦截器的处理,最后通过浏览器 HTTP API 发出。

        不同版本的Angular,以上代码位置行数不同,但是文件位置都是一样的,大家可以通过以上关键字搜索就能找到相关代码。

        类的声明文件路径:

node_modules/@angular/common/http/http.d.ts

        代码源文件路径:文章来源地址https://www.toymoban.com/news/detail-475995.html

node_modules/@angular/common/fesm2015/http.js

到了这里,关于【Angular中的HTTP请求】- HttpClient 详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 为什么mysql使用的是B+树而nosql类型的数据库大多数使用的是LSM树

    MySQL和LSM Tree(一种基于日志的存储引擎)都是关系型数据库,但它们在数据结构的选择上有所不同。 MySQL使用B+树作为其默认的索引结构,因为B+树在某些方面比LSM树更适合作为默认的索引结构。B+树的查询和更新速度相对较快,而且它的写入操作通常是基于内存的。这意味着

    2024年02月06日
    浏览(103)
  • R语言【base】——data.frame():创建数据框,紧耦合的变量集合,它们共享矩阵和列表的许多属性,被大多数R建模软件用作基本数据结构。

    Package  base  version 4.2.0 创建数据框(data frame),紧耦合的变量集合,它们共享矩阵和列表的许多属性,被大多数R建模软件用作基本数据结构。 数据框:一种在统计分析和数据处理中常用的数据结构,由行和列组成,类似于电子表格。 参数【...】:这些参数的形式是 value 或

    2024年02月21日
    浏览(51)
  • HttpClient:HTTP GET请求的服务器响应输出

    前言 在现代软件开发中,与网络通信相关的技术变得愈发重要。Java作为一种强大而灵活的编程语言,提供了丰富的工具和库,用于处理各种网络通信场景。本文将聚焦在Java中使用HttpClient库发送HTTP GET请求,并将服务器的响应数据进行输出,同时加入代理服务器的配置,以应

    2024年02月20日
    浏览(47)
  • HTTP POST接口带参数的HttpClient请求方法和调用

    接口自动化测试,今天遇到POST接口带参数,参数在url上,发现原来的工具类中没有该方法,重新调试加上。  doPost方法如下: 参考: [Java 接口自动化框架]httpclient4.5.3(CloseableHttpClient) https的工具类HttpsClientUtils

    2024年02月06日
    浏览(48)
  • 【微软技术栈】C#.NET 使用 HttpClient 类发出 HTTP 请求

    创建 HttpClient 发出 HTTP 请求 处理 HTTP 响应 HTTP 错误处理 HTTP 代理 本文介绍如何使用  HttpClient  类发出 HTTP 请求和处理响应。  重要 所有示例 HTTP 请求都以下面 URL 之一为目标: https://jsonplaceholder.typicode.com:用于测试和原型设计的免费虚设 API。 https://www.example.com:此域用于

    2024年02月04日
    浏览(39)
  • Spring Boot进阶(72):【教程】用Spring Boot和HttpClient实现高效的HTTP请求

      随着系统规模的不断扩大和复杂度的提升,异步通信这种模式越来越被广泛应用于各种分布式系统中。RocketMQ作为一个高性能、高可靠性、分布式消息队列,得到了众多企业的青睐。本文将介绍如何使用Spring Boot整合RocketMQ,实现异步通信。   那么,具体如何实现呢?这

    2024年02月09日
    浏览(45)
  • HTTP的长连接和短连接详解(HTTP 请求头中的Connection字段)

    参考博客:https://www.cnblogs.com/hls-code/p/15015859.html 前言: HTTP的长连接和短连接本质上是TCP的长连接和短连接。 HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议。 IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠地传递数据包,使得网络

    2024年02月15日
    浏览(46)
  • Angular中RxJS处理一些任务——HTTP请求,表单处理

            此篇是完善https://blog.csdn.net/qq_44327851/article/details/134917018这篇博客,在上篇博客中我们提到了处理异步数据流,那在Angular中有哪些异步数据流呢,又是如何处理的呢?         Angular中的RxJS是一个非常强大和流行的库, 用于处理异步数据流和事件流 。它提供了丰

    2024年02月03日
    浏览(49)
  • 【angular教程240112】09(完) Angular中的数据请求 与 路由

    【angular教程240112】09(完) Angular中的数据请求 与 路由 Angular中的数据请求 内置模块HttpClient实现(get post jsonp 以及第三方模板axios请求数据 一、 Angular get 请求数据 二、 Angular post提交数据 三、 Angular Jsonp请求数据 四、 Angular中使用第三方模块axios请求数据 五、Angular内置模块H

    2024年01月21日
    浏览(47)
  • Angular 17+ 高级教程 – HttpClient

    HttpClient 是 Angular 对 XMLHttpRequest 和 Fetch 的封装。 HttpClient 的 DX (Developer Experience) 比 XMLHttpRequest 和 Fetch 都好,只是学习成本比较高,因为它融入了 RxJS 概念。 要深入理解 HttpClient 最好先掌握 3 个基础技能: XMLHttpRequest -- 看这篇 Fetch -- 看这篇 RxJS -- 看这系列 (如果只是为了

    2024年03月16日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包