概述
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()发起请求即可。
- 导入rcp模块。
- 定义headers,设置可接受的数据内容的类型为json字符串;定义modifiedContent,传入想要修改的内容。
- 调用rcp.createSession()创建通信会话对象session。
- 使用new rcp.Request()方法定义请求对象req。
- 调用session.fetch()方法发起请求。
- 获取响应结果。
核心代码
// 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”。
- 导入rcp模块。
- 定义sessionConfig对象中的baseAddress为http://api.example.com。
- 调用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请求将多个表单数据携带上传至服务端。
- 导入rcp模块。
- 定义请求头类型、配置HTTP请求的超时值、HTTP请求中包含的cookie和设置传输数据范围。
- 调用rcp.createSession()创建通信会话对象。
- 通过new rcp.MultipartForm()设置多表单数据。
- 使用new rcp.Request()定义请求对象,调用session.fetch()方法发起请求。
- 处理响应结果。
核心代码
// 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。
- 导入rcp模块。
- 配置自定义的DNS服务器。
- 调用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 。
- 导入rcp模块。
- 配置静态DNS规则。
- 调用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 。
- 导入rcp模块。
- 定义HTTPS上的DNS对象dohConfig。
- 调用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()方法中根据业务需求自定义处理逻辑,实现对请求/响应的修改。
- 导入rcp模块。
- 定义RequestUrlChangeInterceptor拦截器和ResponseHeaderRemoveInterceptor拦截器。
- 在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,即可在请求/响应中添加拦截器。
- 导入rcp模块、自定义的拦截器。
- 定义sessionConfig对象中的interceptors(传入自定义拦截器)。
- 调用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请求/响应时的详细信息。
- 导入rcp模块。
- 定义tracingConfig对象中的verbose为true,表示启用详细跟踪。
- 定义tracingConfig对象中的infoToCollect对象中的incomingData为true(收集传入的数据信息事件)、outgoingData为true(收集传出的数据信息事件)、incomingHeader为true(收集传入的header信息事件)、outgoingHeader为true(收集传出的header信息事件)。
- 定义tracingConfig对象中collectTimeInfo为true,表示在跟踪过程中收集与时间相关的信息。
- 在HttpEventsHandler中定义onDataReceive(当接收到HTTP响应正文的一部分时调用的回调)、onHeaderReceive(用于在响应期间处理接收到的headers的回调)、onDataEnd(数据传输完成时触发的回调)。
- 调用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的网络请求能力。
转载于:文档中心