鸿蒙 ArkTs 基于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会话后,通过new rcp.Request()的第二个参数指定method为PATCH,然后通过rcp.fetch()发起请求即可。

  1. 导入rcp模块。
  2. 定义headers,设置可接受的数据内容的类型为json字符串;定义modifiedContent,传入想要修改的内容。
  3. 调用rcp.createSession()创建通信会话对象session。
  4. 使用new rcp.Request()方法定义请求对象req。
  5. 调用session.fetch()方法发起请求。
  6. 获取响应结果。

核心代码

// Define the headers
let headers: rcp.RequestHeaders = {
'accept': 'application/json'
};
// Define the content to be modified
let modifiedContent: UserInfo = {
'userName': 'xxxx'
};
// Create the communication session object session
const session = rcp.createSession();
// Define the request object req
let req = new rcp.Request('http://example.com/fetch', 'PATCH', headers, modifiedContent);
// Initiate a request
session.fetch(req).then((response) => {
Logger.info('Request succeeded, message is ' + JSON.stringify(response));
}).catch((err: BusinessError) => {
Logger.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

设置会话中URL的基地址

会话中URL的基地址是在发起请求时用作请求地址的前缀。 当我们向服务器发起请求时,该请求的最终的请求地址由会话中URL的基地址与请求路径来构建的。 这使得我们可以将服务器的主机地址与公共路径隔离开来,方便管理和维护。

实现思路

会话中URL的基地址可通过RCP模块中的SessionConfiguration来进行设置,在sessionConfig对象中定义“baseAddress:'http://api.example.com' ”即可设置会话中URL的基地址为“http://api.example.com”。

  1. 导入rcp模块。
  2. 定义sessionConfig对象中的baseAddress为http://api.example.com。
  3. 调用rcp.createSession()传入sessionConfig,创建通信会话对象session。

核心代码

// Define the sessionConfig object
const sessionConfig: rcp.SessionConfiguration = {
baseAddress: 'http://api.example.com',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
}
};
// Create the communication session object session and input sessionConfig
const session = rcp.createSession(sessionConfig);

实现多表单提交

开发过程中时常会遇到多表单提交的场景,例如在同页面下tab栏可切换多个Form表单组件,但只有一个提交按钮,各组件下的表单数据需要被一起提交。此时可以使用RCP模块中的MultipartForm来实现多表单提交的场景。

实现思路

在创建session会话后,通过new rcp.Request()的第四个参数传入MultipartForm,然后通过rcp.fetch()发起POST请求将多个表单数据携带上传至服务端。

  1. 导入rcp模块。
  2. 定义请求头类型、配置HTTP请求的超时值、HTTP请求中包含的cookie和设置传输数据范围。
  3. 调用rcp.createSession()创建通信会话对象。
  4. 通过new rcp.MultipartForm()设置多表单数据。
  5. 使用new rcp.Request()定义请求对象,调用session.fetch()方法发起请求。
  6. 处理响应结果。

核心代码

// Defines the request header type
let headers: rcp.RequestHeaders = {
'accept': 'application/json'
};
// Configure timeout values for HTTP requests
let configuration: rcp.Configuration = {
transfer: {
timeout: { connectMs: 60000, transferMs: 60000 }
}
};
// Cookies included in the HTTP request
let cookies: rcp.RequestCookies = { 'name1': 'value1', 'name2': 'value2' };
// Setting the Data Transmission Range
let transferRange: rcp.TransferRange = { from: 100, to: 200 };

// Set up multi-form data
const multiForm = new rcp.MultipartForm({
'Form1': this.name, // string
'Form2': this.hobbies, // Arrays
'Form3': {
contentType: 'text/plain',
remoteFileName: 'RemoteFileName',
contentOrPath: '/file/to/Path'
} // object
});

// Creates a communication session object session
const session = rcp.createSession();
// Define the request object req
let req =
new rcp.Request('https://www.example.com', 'POST', headers, multiForm, cookies, transferRange, configuration);
req.content = multiForm;

// Initiate a request
session.fetch(req).then((response) => {
Logger.info('Request succeeded, message is ' + JSON.stringify(response));
}).catch((err: BusinessError) => {
Logger.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

实现双向证书校验

为验证服务端和客户端之间的身份和数据完整性,确保通信的安全性,可使用RCP接口能力实现双向证书校验能力。

详情请参见:双向证书校验

实现对DNS的定制设置

通过RCP模块,能够实现对DNS的定制设置。开发人员可以按自己的需要配置DNS,包括自定义DNS服务器、自定义静态DNS规则和配置HTTPS上的DNS,都可以通过DnsConfiguration设置。DnsConfiguration中可设置dnsRules、dnsOverHttps。

  • dnsRules(配置DNS规则)

    自定义DNS服务器(DnsServers):可指定自定义的DNS服务器提供解析服务。

    自定义静态DNS(StaticDnsRules):有些时候,默认的DNS不能正常解析部分域名,就需要手动添加静态DNS。添加静态DNS后,如果hostname匹配,则优先使用指定的地址。

    自定义动态DNS(DynamicDnsRules):除了添加静态DNS外,还可以添加动态DNS。动态DNS可看作一个可以根据hostname和port直接返回IP地址的函数,如果设置,则优先使用函数中返回的地址。

  • dnsOverHttps

    DNS over HTTPS配置(DnsOverHttpsConfiguration):配置HTTPS上的DNS(DOH)设置,以加密的HTTPS协议进行DNS解析请求,避免原始DNS协议中用户的DNS解析请求被窃听或者修改的问题,来达到保护用户隐私的目的。如果设置,则优先使用DNS服务器解析的地址。

自定义DNS服务器

实现思路

先配置自定义的DNS服务器customDnsServers,在创建session会话时,通过requestConfiguration传入dns对象,指定dns对象中的dnsRules为customDnsServers。

  1. 导入rcp模块。
  2. 配置自定义的DNS服务器。
  3. 调用rcp.createSession()创建通信会话对象时,传入自定义的DNS服务器。

核心代码

// Configure a User-Defined DNS Server
const customDnsServers: rcp.DnsServers = [
{ ip: '8.8.8.8' },
{ ip: '8.8.4.4', port: 53 }
];
// Creating a Communication Session Object
const sessionWithCustomDns = rcp.createSession(
{
requestConfiguration: {
dns: {
dnsRules: customDnsServers
}
}
});
// Initiate a request
sessionWithCustomDns.get('http://www.example.com').then((response) => {
Logger.info('Request succeeded, message is ' + JSON.stringify(response));
}).catch((err: BusinessError) => {
Logger.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

自定义静态DNS

实现思路

先配置静态DNS规则staticDnsRules,在创建session会话时,通过requestConfiguration传入dns对象,指定dns对象中的dnsRules为staticDnsRules 。

  1. 导入rcp模块。
  2. 配置静态DNS规则。
  3. 调用rcp.createSession()创建通信会话对象时,传入静态DNS规则。
// When hostname is matched, the specified address is used preferentially.
const staticDnsRules: rcp.StaticDnsRules = [
{
host: 'example.com',
port: 80,
ipAddresses: ['192.168.1.1', '192.168.1.2']
}
];
// Creating a Communication Session Object
const sessionWithStaticDns =
rcp.createSession({ requestConfiguration: { dns: { dnsRules: staticDnsRules } } });
// Initiate a request
sessionWithStaticDns.get('http://www.example.com').then((response) => {
Logger.info('Request succeeded, message is ' + JSON.stringify(response));
}).catch((err: BusinessError) => {
Logger.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

配置HTTPS上的DNS

实现思路

先定义HTTPS上的DNS对象dohConfig,在创建session会话时,通过requestConfiguration传入dns对象,指定dns对象中的dnsOverHttps为dohConfig 。

  1. 导入rcp模块。
  2. 定义HTTPS上的DNS对象dohConfig。
  3. 调用rcp.createSession()创建通信会话对象时,传入dohConfig。
// DNS over HTTPS Configuration
const dohConfig: rcp.DnsOverHttpsConfiguration = {
url: 'https://dns.example.com/dns-query',
skipCertificatesValidation: true
};
// Creating a Communication Session Object
const sessionWithDoh = rcp.createSession({ requestConfiguration: { dns: { dnsOverHttps: dohConfig } } });
// Initiate a request
sessionWithDoh.get('http://www.example.com').then((response) => {
Logger.info('Request succeeded, message is ' + JSON.stringify(response));
}).catch((err: BusinessError) => {
Logger.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

实现请求与响应拦截

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

拦截器工作原理

客户端发送HTTP请求,到达目标服务器之前,可以使用拦截器对HTTP的请求进行修改。如下图,定义了链式拦截器,RequestUrlChangeInterceptor拦截器(下文以拦截器1代替)和ResponseHeaderRemoveInterceptor拦截器(下文以拦截器2代替)。请求先被拦截器1拦截,该拦截器可以实现当网络质量差时,通过修改HTTP请求中的URL,来调整请求资源的大小。然后经过拦截器2,最后到达Internet。当请求到达目标服务器,服务器返回请求响应的结果给客户端之前,可以使用拦截器对HTTP的响应进行修改。如下图,响应先被拦截器2拦截,在响应返回给应用前检查和修改服务器的请求头。然后经过拦截器1,最后客户端接收响应结果。

说明

RequestUrlChangeInterceptor拦截器和ResponseHeaderRemoveInterceptor拦截器都是自定义拦截器,需要开发者通过代码去实现内部逻辑。

拦截器的定义和使用

下面将介绍如何自定义拦截器,定义RequestUrlChangeInterceptor拦截器和ResponseHeaderRemoveInterceptor拦截器实现rcp.Interceptor,可在intercept()方法中根据业务需求自定义处理逻辑,实现对请求/响应的修改。

  1. 导入rcp模块。
  2. 定义RequestUrlChangeInterceptor拦截器和ResponseHeaderRemoveInterceptor拦截器。
  3. 在intercept()方法中实现对请求/响应的修改逻辑。

核心代码

import { rcp } from '@kit.RemoteCommunicationKit';
import { url } from '@kit.ArkTS';
import { NetworkQualityProvider } from './NetworkStateSimulator';
import Logger from '../common/Logger';

// Define the RequestUrlChangeInterceptor interceptor
export class RequestUrlChangeInterceptor implements rcp.Interceptor {
private readonly networkQualityProvider: NetworkQualityProvider;

constructor(networkQualityProvider: NetworkQualityProvider) {
this.networkQualityProvider = networkQualityProvider;
}

async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
// Customizing Request Processing Logic
if (context.request.method === 'GET' && !this.networkQualityProvider.isNetworkFast()) {
Logger.info('[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];
Logger.info(`[RequestUrlChangeInterceptor]: Replace URL from ${context.request.url.href} to ${changed}`);
AppStorage.setOrCreate('ReplasedInfo',
`[RequestUrlChangeInterceptor]: Replaced URL from ${context.request.url.href} to ${changed}`);
context.request.url = changed;
}
} else {
Logger.info('[RequestUrlChangeInterceptor]: Network is fast');
}
return next.handle(context);
}
}

// Define the ResponseHeaderRemoveInterceptor interceptor
export class ResponseHeaderRemoveInterceptor implements rcp.Interceptor {
// Customizing Response Processing Logic
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-length': response.headers['content-length']
},
effectiveUrl: response.effectiveUrl,
timeInfo: response.timeInfo,
toJSON: () => null
};
Logger.info('[ResponseHeaderRemoveInterceptor]: Response was modified');
return toReturn;
}
}

说明

NetworkQualityProvider中定义了isNetWorkFast(),isNetWorkFast用于在示例代码中模拟网络质量的好坏,这里仅作为场景模拟,需要开发者自行评估实现。

RequestUrlChangeInterceptor拦截器中,当网络质量较差的时候,修改请求中的URL路径,请求获取分辨率较小的图片,可提升用户体验。

下面将介绍如何使用拦截器,可通过RCP模块中的SessionConfiguration来进行设置,在sessionConfig对象中定义interceptors,即可在请求/响应中添加拦截器。

  1. 导入rcp模块、自定义的拦截器。
  2. 定义sessionConfig对象中的interceptors(传入自定义拦截器)。
  3. 调用rcp.createSession()传入sessionConfig,创建通信会话对象session。

核心代码

const sessionConfig: rcp.SessionConfiguration = {
interceptors: [
new RequestUrlChangeInterceptor(networkStateSimulator),
new ResponseHeaderRemoveInterceptor()
]
};

const session = rcp.createSession(sessionConfig);

捕获有关HTTP请求/响应流的详细信息

当需要采集应用中HTTP请求的详细跟踪信息时,可以使用TracingConfiguration进行相关配置。TracingConfiguration中可以设置verbose(启用详细跟踪)、infoToCollect(配置要收集的特定类型的信息事件)、collectTimeInfo(在跟踪过程中是否应收集与时间相关的信息)、httpEventsHandler(为HTTP请求/响应过程中的特定操作定义响应处理程序的回调)四个参数。

下面将以获取HTTP请求/响应时的数据接收时、请求头接收时、数据传输完成时等详细信息为例,进行介绍。

实现思路

通过配置TracingConfiguration中的参数,来捕获HTTP请求/响应时的详细信息。

  1. 导入rcp模块。
  2. 定义tracingConfig对象中的verbose为true,表示启用详细跟踪。
  3. 定义tracingConfig对象中的infoToCollect对象中的incomingData为true(收集传入的数据信息事件)、outgoingData为true(收集传出的数据信息事件)、incomingHeader为true(收集传入的header信息事件)、outgoingHeader为true(收集传出的header信息事件)。
  4. 定义tracingConfig对象中collectTimeInfo为true,表示在跟踪过程中收集与时间相关的信息。
  5. HttpEventsHandler中定义onDataReceive(当接收到HTTP响应正文的一部分时调用的回调)、onHeaderReceive(用于在响应期间处理接收到的headers的回调)、onDataEnd(数据传输完成时触发的回调)。
  6. 调用rcp.createSession()传入tracingConfig ,创建通信会话对象session。

核心代码

// Define a custom response handler
const customHttpEventsHandler: rcp.HttpEventsHandler = {
onDataReceive: (incomingData: ArrayBuffer) => {
// Custom logic for handling incoming data
Logger.info('Received data:' + JSON.stringify(incomingData));
return incomingData.byteLength;
},
onHeaderReceive: (headers: rcp.ResponseHeaders) => {
// Custom logic for handling response headers
Logger.info('Received headers:' + JSON.stringify(headers));
},
onDataEnd: () => {
// Custom logic for handling data transfer completion
Logger.info('Data transfer complete');
},
};

// Configure tracing settings
const tracingConfig: rcp.TracingConfiguration = {
verbose: true,
infoToCollect: {
incomingHeader: true, // Event of collecting the input header information
outgoingHeader: true, // Collect Outgoing Header Information Event
incomingData: true, // Collect Incoming Data Information Event
outgoingData: true // Collect Outgoing Data Information Event
},
collectTimeInfo: true,
httpEventsHandler: customHttpEventsHandler
};

// Use the configuration in the session creation
const session = rcp.createSession({ requestConfiguration: { tracing: tracingConfig } });
session.get('https://developer.huawei.com').then((response) => {
Logger.info('Request succeeded, message is ' + JSON.stringify(response));
}).catch((err: BusinessError) => {
Logger.error(`err: err code is ${err.code}, err message is ${JSON.stringify(err)}`);
});

总结

本文主要介绍了基于RCP实现基础的网络请求、多表单提交、双向证书校验、DNS相关设置、请求与响应拦截、HTTP请求期间捕获详细的跟踪信息等。

  • 调用rcp.createSession()创建通信会话对象,实现基础的网络请求能力。
  • 对标HTTP原生能力,通过new rcp.MultipartForm()可实现多表单提交的场景。
  • 双向证书校验:用于验证服务端和客户端之间的身份和数据完整性,确保通信的安全性。
  • 给HTTP请求配置域名系统(DNS),包括自定义DNS服务器、自定义静态DNS规则和配置HTTPS上的DNS。
  • 定义拦截器对象实现高性能网络资源加载。
  • 使用rcp.TracingConfiguration进行相关配置,在会话中的HTTP请求期间捕获详细的跟踪信息。

完整示例代码开发者可以参考:基于RCP的网络请求能力

转载于:文档中心

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值