HarmonyOS NEXT网络状态监听HTTP和RCP请求网络

当我们在HarmonyOS NEXT中开发的应用,基本上都会使用网络请求,从服务端获取数据在客户端显示或者供用户交互,有时候网络发生变化时,我们需要做一些相应的操作,接下来我们一起来了解下在HarmonyOS NEXT下如何监听网络状态,如何向服务端请求网络

网络监听

网络监听需要声明接口调用所需要的权限:ohos.permission.GET_NETWORK_INFO

1.创建网络对象
 

 从@kit.NetworkKit中导入connection命名空间,创建NetConnection对象

import { connection } from "@kit.NetworkKit";
  
netConnection= connection.createNetConnection(this.netSpecifier, this.timeout)

2.开启网络状态订阅

订阅默认网络状态发生变化的通知,订阅成功后进行后续步骤

openRegister(){
  this.netConnection.register((error:BusinessError)=>{
    hilog.info(0x0000, this.TAG,JSON.stringify(error))
  })
}

3.订阅具体网络变化

订阅具体网络变化事件,如网络可用,网络丢失等

this.netConnection.on('netAvailable',(data:connection.NetHandle)=>{
  promptAction.showToast({message:'当前可用网络:'+JSON.stringify(data),duration:2000});
});

 this.netConnection.on('netLost',()=>{
      promptAction.showToast({message:'网络丢失了',duration:2000});
 });

具体的网络时间主要分为:

参数说明触发时机
netAvailable网络可用事件当设备连接到可用网络时触发
netBlockStatusChange网络阻塞状态事件当建立网络连接超时、传输数据包丢失或网络带宽不足、负载过高时触发
netCapabilitiesChange网络能力变化事件当网络的能力(如类型、带宽等)发生变化时触发
netConnectionPropertiesChange网络连接信息变化事件当网络连接的信息(如IP地址、网关等)发生变化时触发
netLost网络丢失事件当设备失去网络连接时触发
netUnavailable网络不可用事件当设备处于无网络状态或网络不可用时触发

他们的触发条件关系如下图:

4.取消网络状态订阅

应用关闭时取消网络状态订阅,不在接受通知

unRegister(){
  this.netConnection.unregister((error:BusinessError)=>{
    hilog.info(0x0000, this.TAG,'移除网络状态订阅:'+JSON.stringify(error))
  })
}

使用HTTP访问网络

场景介绍

应用通过HTTP发起一个数据请求,支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。

HTTP数据请求功能主要由http模块提供。

使用该功能需要申请ohos.permission.INTERNET权限

request接口开发步骤

  1. 从@kit.NetworkKit中导入http命名空间。
  2. 调用createHttp()方法,创建一个HttpRequest对象。
  3. 调用该对象的on()方法,订阅http响应头事件,此接口会比request请求先返回。可以根据业务需要订阅此消息。
  4. 调用该对象的request()方法,传入http请求的url地址和可选参数,发起网络请求。
  5. 按照实际业务需要,解析返回结果。
  6. 调用该对象的off()方法,取消订阅http响应头事件。
  7. 当该请求使用完毕时,调用destroy()方法主动销毁。
// 引入包名
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();
// 用于订阅HTTP响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息
// 从API 8开始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。 8+
httpRequest.on('headersReceive', (header) => {
  console.info('header: ' + JSON.stringify(header));
});
httpRequest.request(
  // 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
  "EXAMPLE_URL",
  {
    method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET
    // 开发者根据自身业务需要添加header字段
    header: {
      'Content-Type': 'application/json'
    },
    // 当使用POST请求时此字段用于传递请求体内容,具体格式与服务端协商确定
    extraData: "data to send",
    expectDataType: http.HttpDataType.STRING, // 可选,指定返回数据的类型
    usingCache: true, // 可选,默认为true
    priority: 1, // 可选,默认为1
    connectTimeout: 60000, // 可选,默认为60000ms
    readTimeout: 60000, // 可选,默认为60000ms
    usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
    usingProxy: false, // 可选,默认不使用网络代理,自API 10开始支持该属性
    caPath:'/path/to/cacert.pem', // 可选,默认使用系统预制证书,自API 10开始支持该属性
    clientCert: { // 可选,默认不使用客户端证书,自API 11开始支持该属性
      certPath: '/path/to/client.pem', // 默认不使用客户端证书,自API 11开始支持该属性
      keyPath: '/path/to/client.key', // 若证书包含Key信息,传入空字符串,自API 11开始支持该属性
      certType: http.CertType.PEM, // 可选,默认使用PEM,自API 11开始支持该属性
      keyPassword: "passwordToKey" // 可选,输入key文件的密码,自API 11开始支持该属性
    },
    multiFormDataList: [ // 可选,仅当Header中,'content-Type'为'multipart/form-data'时生效,自API 11开始支持该属性
      {
        name: "Part1", // 数据名,自API 11开始支持该属性
        contentType: 'text/plain', // 数据类型,自API 11开始支持该属性
        data: 'Example data', // 可选,数据内容,自API 11开始支持该属性
        remoteFileName: 'example.txt' // 可选,自API 11开始支持该属性
      }, {
        name: "Part2", // 数据名,自API 11开始支持该属性
        contentType: 'text/plain', // 数据类型,自API 11开始支持该属性
        // data/app/el2/100/base/com.example.myapplication/haps/entry/files/fileName.txt
        filePath: `${getContext(this).filesDir}/fileName.txt`, // 可选,传入文件路径,自API 11开始支持该属性
        remoteFileName: 'fileName.txt' // 可选,自API 11开始支持该属性
      }
    ]
  }, (err: BusinessError, data: http.HttpResponse) => {
    if (!err) {
      // data.result为HTTP响应内容,可根据业务需要进行解析
      console.info('Result:' + JSON.stringify(data.result));
      console.info('code:' + JSON.stringify(data.responseCode));
      // data.header为HTTP响应头,可根据业务需要进行解析
      console.info('header:' + JSON.stringify(data.header));
      console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
      // 当该请求使用完毕时,调用destroy方法主动销毁
      httpRequest.destroy();
    } else {
      console.error('error:' + JSON.stringify(err));
      // 取消订阅HTTP响应头事件
      httpRequest.off('headersReceive');
      // 当该请求使用完毕时,调用destroy方法主动销毁
      httpRequest.destroy();
    }
  }
);

做过移动开发的同学应该都清楚,网络请求一般官方都可能会对其再封装,让开发者能够更方便快捷的使用,例如Android原生开发中的OkHttp对HttpClient和Retrofit对OKHTTP

RCP的网络请求开发实践

概述

Remote Communication Kit中的@hms.collaboration.rcp(后续简称RCP)指的是远程通信平台(remote communication platform),RCP提供了网络数据请求功能,相较于Network Kit中HTTP请求能力,RCP更具易用性,且拥有更多的功能。在开发过程中,如果有些场景使用Network Kit中HTTP请求能力达不到预期或无法实现,那么就可以尝试使用RCP中的数据请求功能来实现。

接下来,我们将先介绍RCP与HTTP的区别,然后从使用RCP实现基础的网络请求、多表单提交、双向证书校验、DNS的相关设置、请求与响应拦截和捕获有关HTTP请求/响应流的详细信息等几个场景来介绍RCP拥有的能力

RCP与HTTP的区别

为了方便了解RCP与HTTP的区别,可以从功能分类、功能名称和功能描述这三个方面进行对比,主要区别如下:

功能分类

功能名称

功能描述

HTTP

RCP

基础功能

发送PATCH类型请求

以PATCH的方式请求

不支持

支持

基础功能

设置会话中URL的基地址

会话中URL的基地址将自动加在URL前面,除非URL是一个绝对的URL

不支持

支持

基础功能

取消自动重定向

HTTP请求不会自动重定向

不支持

支持

基础功能

拦截请求和响应

在请求后或响应前进行拦截

不支持

支持

基础功能

取消请求

发送请求前取消、发送请求过程中取消、请求接收后取消

不支持

支持

基础功能

响应缓存

是否使用缓存,请求时优先读取缓存。缓存跟随当前进程生效,新缓存会替换旧缓存

不支持

支持

基础功能

设置响应数据的类型

设置数据以何种方式返回,将要响应的数据类型可设置为string、object、arraybuffer等类型

支持

不支持

基础功能

定义允许的HTTP响应内容的最大字节数

服务器成功响应时,在获取数据前校验响应内容的最大字节数

支持

不支持

证书验证

自定义证书校验

自定义逻辑校验客户端和服务端的证书,判断是否可以连接

不支持

支持

证书验证

忽略SSL校验

在建立SSL连接时不验证服务器端的SSL证书

不支持

支持

DNS

自定义DNS解析

包括自定义DNS服务器或静态DNS规则

不支持

支持

rcp特有

捕获详细的跟踪信息

在会话中的HTTP请求期间捕获详细的跟踪信息。跟踪有助于调试、性能分析和深入了解通信过程中的数据流

不支持

支持

rcp特有

数据打点,获取HTTP请求的具体数据

HTTP请求各阶段的定时信息

不支持

支持

实现网络请求

发送请求

通过RCP模块能够发起基础的网络请求,如GET、POST、HEAD、PUT、DELETE、PATCH、OPTIONS等请求。以PATCH请求为例,开发过程中经常会遇到发送请求修改资源的场景,假设有一个UserInfo,里面有userId、userName、 userGender等10个字段。可编辑功能因为需求,在某个特别的页面里只能修改userName,这时就可以用PATCH请求,来更新局部资源。

实现思路

在创建session会话后,通过创建请求对象并传入第二个参数且指定为PATCH,然后通过session.fetch()发起请求即可。

  1. 导入rcp模块。
  2. 创建通信会话对象调用rcp.createSession()创建通信会话对象session。
  3. 使用new rcp.Request()方法创建请求对象req。
  4. 调用session.fetch()方法发起请求。
  5. 获取响应结果。
  6. 销毁对象,释放资源。
核心代码
import rcp from '@hms.collaboration.rcp';

/**
 * @FileName : RCPUtils
 * @Author : kirk.wang
 * @Time : 2025/2/14 16:52
 * @Description : 文件描述
 */
export class  RCPUtils{
  rcpSession:rcp.Session;

  constructor() {
    //1创建Session对象
    this.rcpSession = rcp.createSession();
  }
  //2发起请求
async getRCPRequest(exterData:string):Promise<ResponseDataBean>{
    let respData :ResponseDataBean = new ResponseDataBean() ;
  await this.rcpSession.get('this.url').then((response)=>{
    //3处理响应
      respData  = response.toJSON() as ResponseDataBean;
  });
  await this.rcpSession.post('this.url',exterData).then((response)=>{
    //3处理响应
      respData  = response.toJSON() as ResponseDataBean;
  });

	return respData;
}


  //4销毁对象 ,当该请求使用完毕时,必须调用close方法主动释放与此会话关联的资源
destroySession(){
    this.rcpSession.close()
}

}
export class  ResponseDataBean{

}

我们可以将RCP理解成Retrofit基于OKHttp的封装。

实现请求与响应拦截

使用拦截器可以方便的对HTTP的请求与响应进行修改,您可以创建拦截器链,按需定制一组拦截器对您的网络请求/响应进行修改。RCP模块提供了拦截器能力,在SessionConfiguration中添加Interceptors参数,传入自定义的拦截器,即可在HTTP请求和响应的过程中添加拦截器功能

实现步骤
  1. 导入rcp模块。
  2. 定义RequestUrlChangeInterceptor拦截器和ResponseHeaderRemoveInterceptor拦截器。
  3. 在intercept()方法中实现对请求/响应的修改逻辑
核心代码
import { rcp } from "@kit.RemoteCommunicationKit";
import { url } from "@kit.ArkTS";
import { hilog } from "@kit.PerformanceAnalysisKit";
import { ConnectionUtils } from "./ConnectionUtils";

/**
 * @FileName : RequestUrlChangeInterceptor
 * @Author : kirk.wang
 * @Time : 2025/2/16 17:34
 * @Description :  定义RequestUrlChangeInterceptor拦截器
 */
export class RequestUrlChangeInterceptor implements rcp.Interceptor {
   TAG = "RequestUrlChangeInterceptor"
   
  // 自定义请求处理逻辑
  async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
    if (context.request.method === 'GET' && ConnectionUtils.isNetworkFast()) {
      hilog.info(0x0000, this.TAG,'[RequestUrlChangeInterceptor]: Slow network is detected');
      const parts = context.request.url.pathname.split('.');
      if (parts.length === 2) {
        const changed = url.URL.parseURL(context.request.url.href);
        changed.pathname = parts[0] + '_small.' + parts[1];
        hilog.info(0x0000, this.TAG,`[RequestUrlChangeInterceptor]: Replace URL from "${context.request.url.href}" to "${changed}"`);
        AppStorage.setOrCreate('ReplacedInfo',`[RequestUrlChangeInterceptor]: Replace URL from "${context.request.url.href}" to "${changed}"`);
        context.request.url = changed;
      }
    } else {
      hilog.info(0x0000, this.TAG,'[RequestUrlChangeInterceptor]: Network is fast');
    }
    return next.handle(context);
  }
}

// 定义ResponseHeaderRemoveInterceptor拦截器
export class ResponseHeaderRemoveInterceptor implements rcp.Interceptor {
  TAG = "ResponseHeaderRemoveInterceptor"

  // 自定义响应处理逻辑
  async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
    const response = await next.handle(context);
    const toReturn: rcp.Response = {
      request: response.request,
      statusCode: response.statusCode,
      httpVersion: response.httpVersion,
      headers: {
        'content-range': response.headers['content-range']
      },
      effectiveUrl: response.effectiveUrl,
      timeInfo: response.timeInfo,
      toJSON: () => null
    };
    hilog.info(0x0000, this.TAG,'[ResponseHeaderRemoveInterceptor]: Response was modified');
    return toReturn;
  }
}
拦截器的使用

可通过RCP模块中的SessionConfiguration来进行设置,在sessionConfig对象中设置interceptors,即可在请求/响应中添加拦截器

const sessionConfig: rcp.SessionConfiguration = {
  interceptors: [
    new RequestUrlChangeInterceptor(),
    new ResponseHeaderRemoveInterceptor()
  ],
  requestConfiguration:{ security: this.securityConfig }
  }
};

const session = rcp.createSession(sessionConfig);

和安卓的拦截器使用方法很相似,我们可以在拦截器里做加解密或者自定义header的处理。

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

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

相关文章

如何在 VS Code 中快速使用 Copilot 来辅助开发

在日常开发中&#xff0c;编写代码往往是最耗时的环节之一。而 GitHub Copilot&#xff0c;作为一款 AI 编码助手&#xff0c;可以帮助开发者 自动补全代码、生成代码片段&#xff0c;甚至直接编写完整的函数&#xff0c;大幅提升编码效率。那么&#xff0c;如何在 VS Code 中快…

【16届蓝桥杯寒假刷题营】第2期DAY1I

4.有向无环的路径数 - 蓝桥云课 问题描述 给定 N 个节点 M 条边的有向无环图&#xff0c;请你求解有多少条 1 到 N 的路径。 由于答案可能很大&#xff0c;你只需要输出答案对 998244353 取模后的结果。 输入格式 第一行包含 2 个正整数 N,M&#xff0c;表示有向无环图的节…

伯克利 CS61A 课堂笔记 10 —— Trees

本系列为加州伯克利大学著名 Python 基础课程 CS61A 的课堂笔记整理&#xff0c;全英文内容&#xff0c;文末附词汇解释。 目录 01 Trees 树 Ⅰ Tree Abstraction Ⅱ Implementing the Tree Abstraction 02 Tree Processing 建树过程 Ⅰ Fibonacci tree Ⅱ Tree Process…

Spring Boot 定时任务:轻松实现任务自动化

在现代应用开发中&#xff0c;定时任务是一个常见的需求。比如&#xff0c;我们可能需要定时清理过期数据、定时发送邮件通知等。 操作流程 开启定时任务注解 在启动类添加注解EnableScheduling 设置时间&#xff08;固定时间间隔&#xff09; 使用 Scheduled 注解创建定时…

通过监督微调提升多语言大语言模型性能

引言 澳鹏助力一家全球科技公司提升其大语言模型&#xff08;LLM&#xff09;的性能。通过提供结构化的人工反馈形式的大语言模型训练数据&#xff0c;让该模型在30多种语言、70多种方言中的表现得到优化。众包人员们进行多轮对话&#xff0c;并依据回复的相关性、连贯性、准确…

Flask实现高效日志记录模块

目录 一. 简介&#xff1a; 1. 为什么需要请求日志 二. 日志模块组成 1. 对应日志表创建&#xff08;包含日志记录的关键字段&#xff09; 2. 编写日志记录静态方法 3. 在Flask中捕获请求日志 4. 捕获异常并记录错误日志 5. 编写日志接口数据展示 6. 写入数据展…

【学习笔记】Cadence电子设计全流程(一)Cadence 生态及相关概念

【学习笔记】Cadence电子设计全流程&#xff08;一&#xff09;Cadence 生态及相关概念 1.1 Cadence 生态系统及各模块关系1.2 Cadence相较于Altium Designer在硬件设计中的优势 1.1 Cadence 生态系统及各模块关系 Cadence 提供了一套完整的电子设计自动化 (EDA) 工具链&#…

【Linux Redis】关于用docker拉取Redis后,让虚拟机运行起来redis,并使得其可以连接到虚拟机外的navicat。

步骤一&#xff1a;拉取Redis镜像 docker pull redis 这个命令会下载最新版本的Redis镜像到你的本地Docker仓库中。你也可以指定一个具体的版本号&#xff0c;例如docker pull redis:6.2.6&#xff0c;来拉取特定版本的Redis镜像。 如果拉取遇到问题请参考【Linux AnolisOS】关…

蓝桥与力扣刷题(蓝桥 裁纸刀)

本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 题目&#xff1a;小蓝有一个裁纸刀&#xff0c;每次可以将一张纸沿一条直线裁成两半。 小蓝用一张纸打印出两行三列共 6 个二维码&#xff0c;至少使用九次裁出来&#xff0c…

pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原

pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原 在数字化办公的浪潮中&#xff0c;文档格式转换常常让人头疼不已&#xff0c;尤其是 PDF 转 Word 的需求极为常见。PDF 格式虽然方便阅读和传输&#xff0c;但难以编辑&#xff0c;而 Word 格式却能灵活地进行内容修…

Django ModelForm使用(初学)

1.目的是根据员工表字段&#xff0c;实现一个新增员工的数据填写页面 2.在views.py文件中按下面的格式写 定义 ModelForm 类&#xff1a;UserModelForm &#xff08;自己命名的类名&#xff09;使用时需要导入包 定义视图函数&#xff1a;user_model_form_add&#xff08;在函…

基于大牛直播SDK的Android平台低延迟RTSP|RTMP播放与录像技术实践

技术背景 随着直播、安防监控、远程会议等场景对实时性与稳定性要求的提升&#xff0c;低延迟流媒体播放与录像成为核心技术需求。大牛直播SDK的SmartPlayer模块提供了完整的解决方案&#xff0c;支持RTSP、RTMP协议的多实例播放、硬件解码、实时快照、录像管理等功能&#xf…

小怿学习日记(七) | Unreal引擎灯光架构

灯光的布局对于HMI场景中车模的展示效果有着举足轻重的地位。本篇内容将简单介绍ES3.1的相关知识&#xff0c;再深入了解Unreal引擎中车模的灯光以及灯光架构。 一、关于ES3.1 1.1 什么是ES3.1 ES3.1这个概念对于美术的同学可能比较陌生&#xff0c;ES3.1指的是OpenGL ES3.1&…

DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)

前言 在当今数字化时代&#xff0c;AI编程助手已成为提升开发效率的利器。DeepSeek作为一款强大的AI模型&#xff0c;凭借其出色的性能和开源免费的优势&#xff0c;成为许多开发者的首选。今天&#xff0c;就让我们一起探索如何将DeepSeek接入PyCharm&#xff0c;实现高效、智…

广度优先搜索详解--BFS--蒟蒻的学习之路

1.什么是广度优先搜索? 广度优先搜索&#xff08;Breadth-First Search&#xff0c;简称BFS&#xff09;是一种遍历或搜索树和图的算法&#xff0c;也称为宽度优先搜索&#xff0c;BFS算法从图的某个节点开始&#xff0c;依次对其所有相邻节点进行探索和遍历&#xff0c;然后再…

. Unable to find a @SpringBootConfiguration(默认软件包中的 Spring Boot 应用程序)

解决&#xff1a; 新建一个包即可 问题&#xff1a; 默认软件包中的 Spring Boot 应用程序。 原因&#xff1a; 默认包的定义 &#xff1a; 如果一个 Java 类没有使用 package 声明包名&#xff0c;则该类会被放置在默认包中。Spring Boot 遵循 Java 的包管理约定&#xff…

DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地

对于个人开发者或尝鲜者而言&#xff0c;本地想要部署 DeepSeek 有很多种方案&#xff0c;但是一旦涉及到企业级部署&#xff0c;则步骤将会繁琐很多。 比如我们的第一步就需要先根据实际业务场景评估出我们到底需要部署什么规格的模型&#xff0c;以及我们所要部署的模型&…

“三次握手”与“四次挥手”:TCP传输控制协议连接过程

目录 什么是TCP协议 “三次握手”建立连接 “四次挥手”断开连接 “三次握手”和“四次挥手”的反思 总结 什么是TCP协议 想象一下&#xff0c;你和远方的朋友要进行一场电话交流&#xff0c;但这通电话不仅仅是随便聊聊&#xff0c;而是要传递一封重要的信件。为了确保这…

网络运维学习笔记 012网工初级(HCIA-Datacom与CCNA-EI)某机构新增:GRE隧道与EBGP实施

文章目录 GRE隧道&#xff08;通用路由封装&#xff0c;Generic Routing Encapsulation&#xff09;协议号47实验&#xff1a;思科&#xff1a;开始实施&#xff1a; 华为&#xff1a;开始实施&#xff1a; eBGP实施思科&#xff1a;华为&#xff1a; GRE隧道&#xff08;通用路…

Android 动态加入Activity 时 manifest 注册报错解决。使用manifestPlaceholders 占位

需求如下&#xff1a; 项目 测试demo 有多个渠道&#xff0c;部分渠道包含支付功能&#xff0c;在主测试代码外&#xff0c;需要一个单独 Activity 调用测试代码。 MainActivityPayActivity渠道A包含不包含渠道B包含包含 因为支付功能需要引入对应的 moudule&#xff0c;因此…