鸿蒙网络编程系列32-基于拦截器的性能监控示例

1. 拦截器简介

在Web开发中拦截器是一种非常有用的模式,它允许开发者在请求发送到服务器之前或响应返回给客户端之前执行一些预处理或后处理操作。这种机制特别适用于需要对所有网络请求或响应进行统一处理的情况,比如添加全局错误处理、请求头的修改、响应数据的格式化等,本示例将使用RCP模块提供的拦截器功能,实现对HTTP请求的性能监控,为简单起见,本示例只记录每个HTTP请求和响应的时间以及相关的状态信息,读者可以根据需要记录更多的信息并在此基础上进行深入的统计分析。

在RCP模块的API中,拦截器是以接口的形式提供的,接口名称为Interceptor,包括名称为intercept的一个方法:

intercept(context: RequestContext, next: RequestHandler): Promise<Response>

该方法第一个参数context为请求上下文,第二参数next为下一个请求处理器,可以返回Response的Promise对象,或者返回next调用handle方法的值。

2. 拦截器性能监控演示

本示例运行后的界面如图所示:

这里列出了5个可以请求的web地址,输入要请求的次数,然后单击“随机请求”按钮,应用会随机请求地址列表中的web地址,拦截器会在下方的日志区域实时显示请求性能信息,如图所示:

3. 拦截器性能监控示例编写

下面详细介绍创建该示例的步骤。
步骤1:创建Empty Ability项目。
步骤2:在module.json5配置文件加上对权限的声明:

"requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]

这里添加了访问互联网的权限。
步骤3:在Index.ets文件里添加如下的代码:

import { rcp } from '@kit.RemoteCommunicationKit';

@ObservedV2
  //拦截日志类
class RequestPerfRecord {
  @Trace public id: string = ""
  @Trace public method: string = ""
  @Trace public begin: Date = new Date()
  @Trace public end: Date = new Date()
  @Trace public requestUrl: string = ""
  @Trace public stateCode: number = -1

  constructor(request: rcp.Request) {
    this.id = request.id
    this.method = request.method
    this.begin = new Date()
    this.requestUrl = request.url.toString()
  }

  //请求耗费的秒数
  public spendTime(): number {
    return (this.end.valueOf() - this.begin.valueOf()) / 1000
  }

  public toString(): string {
    if (this.stateCode == -1) {
      return `请求地址:${this.requestUrl}\r\n请求方法:${this.method}\r\n` +
        `请求开始时间:${this.begin.toLocaleString()} \r\n`
    } else {
      return `请求地址:${this.requestUrl}\r\n请求方法:${this.method}\r\n` +
        `请求开始时间:${this.begin.toLocaleString()}\r\n响应时间:${this.end.toLocaleString()} \r\n` +
        `请求响应耗时:${this.spendTime()}秒\r\n` +
        `响应状态码:${this.stateCode}\r\n`
    }
  }
}

@Entry
@ComponentV2
struct Index {
  @Local title: string = '基于拦截器的HTTP请求性能监控';
  //请求地址列表
  @Local requestUrlList: Array<string> =
    ["https://www.baidu.com", "https://www.baidu.com/nopage.html", "https://www.aliyun.com/"
      , "https://developer.huawei.com/consumer/cn/forum/", "https://www.zhihu.com/"]
  //请求次数
  @Local requestTimes: number = 5
  //拦截日志列表
  @Local requestPerRecordList: Array<RequestPerfRecord> = new Array()
  scroller: Scroller = new Scroller()

  build() {
    Row() {
      Column() {
        Text(this.title)
          .fontSize(14)
          .fontWeight(FontWeight.Bold)
          .width('100%')
          .textAlign(TextAlign.Center)
          .padding(5)

        Text("请求地址列表:")
          .fontSize(14)
          .width('100%')
          .padding(5)

        List({ space: 5, initialIndex: 0 }) {
          ForEach(this.requestUrlList, (item: string) => {
            ListItem() {
              Text(item)
                .fontSize(13)
            }
          }, (item: string) => item)
        }.width('100%')
        .padding(5)

        Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
          Text("请求次数:")
            .fontSize(14)
            .width(80)

          Counter() {
            Text(this.requestTimes.toString())
          }
          .onInc(() => {
            this.requestTimes++
          })
          .onDec(() => {
            this.requestTimes--
          })
          .width(140)
          .padding(10)
          .height(50)

          Button("随机请求")
            .onClick(() => {
              this.requestTest()
            })
            .width(100)
            .fontSize(14)
        }
        .width('100%')
        .padding(5)

        Scroll(this.scroller) {
          List({ space: 5, initialIndex: 0 }) {
            ForEach(this.requestPerRecordList, (item: RequestPerfRecord) => {
              ListItem() {
                Text(item.toString())
                  .fontSize(13)
              }
            }, (item: string) => item)
          }.width('100%')
          .padding(5)
        }
        .align(Alignment.Top)
        .backgroundColor(0xeeeeee)
        .height(300)
        .flexGrow(1)
        .scrollable(ScrollDirection.Vertical)
        .scrollBar(BarState.On)
        .scrollBarWidth(20)
      }
      .width('100%')
      .justifyContent(FlexAlign.Start)
      .height('100%')
    }
    .height('100%')
  }

  async requestTest() {
    let cfg: rcp.SessionConfiguration = {
      interceptors: [new PerfInterceptor(this.requestPerRecordList)]
    }

    const session = rcp.createSession(cfg);

    for (let i = 0; i < this.requestTimes; i++) {
      let index = Math.floor(Math.random() * this.requestUrlList.length)
      await session.get(this.requestUrlList[index])
      let sleepTime = Math.random() * 5 + 1
      await sleep(sleepTime)
    }
  }
}

//休眠指定的毫秒数
function sleep(time: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, time));
}

//性能监控拦截器
class PerfInterceptor implements rcp.Interceptor {
  requestPerList: Array<RequestPerfRecord>

  constructor(requestPerList: Array<RequestPerfRecord>) {
    this.requestPerList = requestPerList
  }

  //拦截方法
  async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
    let record = new RequestPerfRecord(context.request)
    this.requestPerList.push(record)
    const promise = next.handle(context);
    promise.then((resp) => {
      record.stateCode = resp.statusCode;
      record.end = new Date()
    });
    return promise;
  }
}

步骤4:编译运行,可以使用模拟器或者真机。

步骤5:按照本节第1部分“拦截器性能监控演示”操作即可。

4. 代码分析

本示例的关键点在于记录HTTP请求及响应的时间,这是通过拦截器的intercept方法实现的,该方法首先记录当前的时间,也就是请求发起的时间,然后调用next的handle方法,该方法会发起HTTP请求并返回响应,在该方法的响应处理回调函数中,再次记录当时的时间,也就是响应返回的时间,这样就拿到了最关键的两个时间信息,具体代码如下所示:

async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
    let record = new RequestPerfRecord(context.request)
    this.requestPerList.push(record)
    const promise = next.handle(context);
    promise.then((resp) => {
      record.stateCode = resp.statusCode;
      record.end = new Date()
    });
    return promise;
  }

另外,因为需要把记录的信息在应用界面上展示,所以把状态变量requestPerRecordList传递到了拦截器实例中,这样拦截器生成的HTTP请求日志信息也就保存到了requestPerRecordList变量中,从而可以在界面上随时看到拦截日志。

(本文作者原创,除非明确授权禁止转载)

本文源码地址:
https://gitee.com/zl3624/harmonyos_network_samples/tree/master/code/rcp/HttpRequestMonitor

本系列源码地址:
https://gitee.com/zl3624/harmonyos_network_samples

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/901848.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】【OpenVINO】【C++】模型转化、环境搭建以及模型部署的详细教程

【深度学习】【OpenVINO】【C】模型转化、环境搭建以及模型部署的详细教程 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【OpenVINO】【C】模型转化、环境搭建以及模型部署的详细教程前言模型转换--pytorch转onnxWindows平台搭建…

我们可以用微服务创建状态机吗?

大家好&#xff0c;我是锋哥。今天分享关于【我们可以用微服务创建状态机吗&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; 我们可以用微服务创建状态机吗&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 是的&#xff0c;微服务架构可…

为什么选择 Spring data hadoop

&#x1f449; 请点赞支持这款 全新设计的脚手架 &#xff0c;让 Java 再次伟大&#xff01; spring-data-hadoop hbase 常见的操作方式有以下三种&#xff1a; Native Api 原生 api 操作繁琐&#xff0c;就像用 JDBC 操作关系型数据库一样&#xff0c;类似 flush、submit、…

Windows系统启动MongoDB报错无法连接服务器

文章目录 发现问题解决办法 发现问题 1&#xff09;、先是发现执行 mongo 命令&#xff0c;启动报错&#xff1a; error: MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017&#xff1b; 2&#xff09;、再检查 MongoDB 进程 tasklist | findstr mongo 发现没有进程&a…

【最全基础知识2】机器视觉系统硬件组成之工业相机镜头篇--51camera

机器视觉系统中,工业镜头作为必备的器件之一,须和工业相机搭配。工业镜头是机器视觉系统中不可或缺的重要组成部分,其质量和性能直接影响到整个系统的成像质量和检测精度。 目录 一、基本功能和作用 二、分类 1、按成像方式分 2、按焦距分 3、按接口类型分 4、按应用…

时间序列预测(九)——门控循环单元网络(GRU)

目录 一、GRU结构 二、GRU核心思想 1、更新门&#xff08;Update Gate&#xff09;&#xff1a;决定了当前时刻隐藏状态中旧状态和新候选状态的混合比例。 2、重置门&#xff08;Reset Gate&#xff09;&#xff1a;用于控制前一时刻隐藏状态对当前候选隐藏状态的影响程度。…

STM32实现毫秒级时间同步

提起“时间同步”这个概念&#xff0c;大家可能很陌生。一时间搞不清楚是什么意思。 我理解“时间同步”可以解决多个传感器采集数据不同时的问题&#xff0c;让多个传感器同时采集数据。 打个比方。两个人走路&#xff0c;都是100毫秒走一步&#xff08;频率相同是前提&…

2024数学分析【南昌大学】

计算极限 lim ⁡ n → ∞ 2024 n ( 1 − cos ⁡ 1 n 2 ) n 3 1 + n 2 − n \mathop {\lim }\limits_{n \to \infty } \frac{{\sqrt[n]{{2024}}\left( {1 - \cos \frac{1}{{{n^2}}}} \right){n^3}}}{{\sqrt {1 + {n^2}} - n}} n→∞lim​1+n2 ​−nn2024 ​(1−cosn21​)n3​ …

XJ02、消费金融|消费金融业务模式中的主要主体

根据所持有牌照类型的不同,消费金融服务供给方主要分为商业银行、汽车金融公司、消费金融公司和小贷公司,不同类型机构定位不同、提供消费金融服务与产品类型也各不相同。此外,互联网金融平台也成为中国消费金融业务最重要的参与方之一,虽其并非持牌金融机构,但借助其流量…

React 分装webSocket

背景 AI 实时对话 需要流式数据 React Hooks 写法。新建WebSocket.tsx 放在根目录components import { useCallback, useRef, useState } from react;type MessageHandler (message: MessageEvent) > void; type ErrorHandler (event: Event) > void;export functi…

深度学习(一)基础:神经网络、训练过程与激活函数(1/10)

深度学习基础&#xff1a;神经网络、训练过程与激活函数 引言&#xff1a; 深度学习作为机器学习的一个子领域&#xff0c;近年来在人工智能的发展中扮演了举足轻重的角色。它通过模仿人脑的神经网络结构&#xff0c;使得计算机能够从数据中学习复杂的模式和特征&#xff0c;…

List、Set、数据结构、Collections

一、数据结构 1.1 常用的数据结构 栈 栈&#xff1a;stack,又称堆栈&#xff0c;它是运算受限的线性表&#xff0c;其限制是仅允许在标的一端进行插入和删除操作&#xff0c;不允许在其他任何位置进行添加、查找、删除等操作。 简单的说&#xff1a;采用该结构的集合&#…

【网络协议栈】Tcp协议(下)的可靠性和高效性(超时重传、快速重传、拥塞控制、流量控制)

绪论: 承接上文&#xff0c;上文写到Tcp协议的结构以及对tcp协议的性能优化的滑动窗口&#xff0c;本章我们将继续了解Tcp协议的可靠性和高效性的具体展示。后面我将继续完善网络协议栈的网络层协议敬请期待&#xff01; 话不多说安全带系好&#xff0c;发车啦&#xff08;建议…

【AI绘画】Midjourney进阶:对角线构图详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;什么是构图为什么Midjourney要使用构图 &#x1f4af;对角线构图特点应用场景提示词书写技巧测试 &#x1f4af;小结 &#x1f4af;前言 【AI绘画】Midjourney进阶&a…

Linux常用命令1

切换目录 cd [rootlocalhost menge]# cd /[rootlocalhost /]# cd: cd [-L|[-P [-e]] [-]] [目录] 查看当前的目录 pwd 浏览目录内容 ls ls浏览后颜色表示 白色&#xff1a;普通文件 蓝色&#xff1a;目录 红色&#xff1a;压缩包文件 黄色&#xff1a;设备文件 绿…

以 6502 为例讲讲怎么阅读 CPU 电路图

开篇 你是否曾对 CPU 的工作原理充满好奇&#xff0c;以及简单的晶体管又是如何组成逻辑门&#xff0c;进而构建出复杂的逻辑电路实现&#xff1f;本文将以知名的 6502 CPU 的电路图为例&#xff0c;介绍如何阅读 CPU 电路图&#xff0c;并向你演示如何从晶体管电路还原出逻辑…

.NET Core WebApi第2讲:前后端分离,Restful

动态页面&#xff1a;数据流动 / Web服务器 / Ajax / 前后端分离 / restful风格源栈课堂一起帮https://17bang.ren/Code/261 一、Ajax&#xff1a;页面可以局部刷新 1、PPT演示:使用Ajax也无法减小带宽耗用 请求第一个页面&#xff0c;用AJAX从服务器端加载了一个页头。 请求第…

Maven进阶——坐标、依赖、仓库

目录 1.pomxml文件 2. 坐标 2.1 坐标的概念 2.2 坐标的意义 2.3 坐标的含义 2.4 自己项目的坐标 2.5 第三方项目坐标 3. 依赖 3.1 依赖的意义 3.2 依赖的使用 3.3 第三方依赖的查找方法 3.4 依赖范围 3.5 依赖传递和可选依赖 3.5.1 依赖传递 3.5.2 依赖范围对传…

ollama 在 Linux 环境的安装

ollama 在 Linux 环境的安装 介绍 他的存在在我看来跟 docker 的很是相似&#xff0c;他把市面上已经存在的大语言模型集合在一个仓库中&#xff0c;然后通过 ollama 的方式来管理这些大语言模型 下载 # 可以直接通过 http 的方式吧对应的 shell 脚本下载下来&#xff0c;然…

【10天速通Navigation2】(三) :Cartographer建图算法配置:从仿真到实车,从原理到实现

前言 往期内容&#xff1a; 第一期&#xff1a;【10天速通Navigation2】(一) 框架总览和概念解释第二期&#xff1a;【10天速通Navigation2】(二) &#xff1a;ROS2gazebo阿克曼小车模型搭建-gazebo_ackermann_drive等插件的配置和说明 本教材将贯穿nav2的全部内容&#xff0c…