鸿蒙NEXT开发【基于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的区别,可以从功能分类、功能名称和功能描述这三个方面进行对比,主要区别如下:

功能分类功能名称功能描述HTTPRCP
基础功能发送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. 创建headers,设置可接受的数据内容的类型为json字符串;创建modifiedContent,传入想要修改的内容。
  3. 调用rcp.createSession()创建通信会话对象session。
  4. 使用new rcp.Request()方法创建请求对象req。
  5. 调用session.fetch()方法发起请求。
  6. 获取响应结果。

核心代码

// 定义请求头
let headers: rcp.RequestHeaders = {
  'accept': 'application/json'
};
// 定义要修改的内容
let modifiedContent: UserInfo = {
  'userName': 'xxxxxx'
};
const securityConfig: rcp.SecurityConfiguration = {
  tlsOptions: {
    tlsVersion: 'TlsV1.3'
  }
};
// 创建通信会话对象
const session = rcp.createSession({ requestConfiguration: { security: securityConfig } });
// 定义请求对象rep
let req = new rcp.Request('http://example.com/fetch', 'PATCH', headers, modifiedContent);
// 发起请求
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’ ”即可。

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

核心代码

// 定义sessionConfig对象
const sessionConfig: rcp.SessionConfiguration = {
  baseAddress: 'http://api.example.com',
  headers: {
    'authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'content-type': 'application/json'
  },
  requestConfiguration:{
    security:{
      tlsOptions: {
        tlsVersion: 'TlsV1.3'
      }
    }
  }
};
// 创建通信会话对象,并传入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. 处理响应结果。

核心代码

// 定义请求头类型
let headers: rcp.RequestHeaders = {
  'accept': 'application/json'
};
// 配置HTTP请求的超时值
let configuration: rcp.Configuration = {
  transfer: {
    timeout: {
      connectMs: 60000,
      transferMs: 60000
    }
  }
};
// HTTP请求中的Cookie
let cookies: rcp.RequestCookies = {
  'name1': 'value1',
  'name2': 'value2',
};
// 设置数据传输范围
let transferRange: rcp.TransferRange = {
  from: 100,
  to: 200
};

// 设置multipartFrom数据
const multiForm = new rcp.MultipartForm({
  'Form1': this.name, // string
  'Form2': this.hobbies, // string
  'Form3': {
    contentType: 'text/plain',
    remoteFileName: 'RemoteFileName',
    contentOrPath: '/file/to/Path'
  } // object
});

const securityConfig: rcp.SecurityConfiguration = {
  tlsOptions: {
    tlsVersion: 'TlsV1.3'
  }
};
// 创建通信会话对象
const session = rcp.createSession({ requestConfiguration: { security: securityConfig } });
// 定义请求对象req
let req =
  new rcp.Request('https://www.example.com', 'POST', headers, multiForm, cookies, transferRange, configuration);
req.content = multiForm;

// 发起请求
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服务器。

核心代码

// 配置自定义DNS服务器
const customDnsServers: rcp.DnsServers = [
  { ip: '8.8.8.8' },
  { ip: '8.8.4.4', port: 53 }
];
// 创建通信会话对象
const sessionWithCustomDns = rcp.createSession({
  requestConfiguration: {
    dns: {
      dnsRules: customDnsServers
    },
    security: {
      tlsOptions: {
        tlsVersion: 'TlsV1.3'
      }
    }
  }
});
// 发起请求
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规则。
// 当匹配到hostname时,优先使用指定的地址
const staticDnsRules: rcp.StaticDnsRules = [
  {
    host: 'example.com',
    port: 80,
    ipAddresses: ['192.168.1.1', '192.168.1.2']
  }
];
// 创建通信会话对象
const sessionWithCustomDns = rcp.createSession({
  requestConfiguration: {
    dns: {
      dnsRules: staticDnsRules
    },
    security: {
      tlsOptions: {
        tlsVersion: 'TlsV1.3'
      }
    }
  }
});
// 发起请求
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)}`);
});

配置HTTPS上的DNS

实现思路

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

  1. 导入rcp模块。
  2. 创建HTTPS上的DNS对象dohConfig。
  3. 调用rcp.createSession()创建通信会话对象时,传入dohConfig。
// DNS over HTTPS配置
const dohConfig: rcp.DnsOverHttpsConfiguration = {
  url: 'https://dns.example.com/dns-query',
  skipCertificatesValidation: true
};
// 创建通信会话对象
const sessionWithCustomDns = rcp.createSession({
  requestConfiguration: {
    dns: {
      dnsOverHttps: dohConfig
    },
    security: {
      tlsOptions: {
        tlsVersion: 'TlsV1.3'
      }
    }
  }
});
// 发起请求
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)}`);
});

实现请求与响应拦截

使用拦截器可以方便的对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 Logger from '../common/Logger';
import { NetworkQualityProvider } from './NetworkStateSimulator';

// 定义RequestUrlChangeInterceptor拦截器
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> {
    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('ReplacedInfo',`[RequestUrlChangeInterceptor]: Replace URL from "${context.request.url.href}" to "${changed}"`);
        context.request.url = changed;
      }
    } else {
      Logger.info('[RequestUrlChangeInterceptor]: Network is fast');
    }
    return next.handle(context);
  }
}

// 定义ResponseHeaderRemoveInterceptor拦截器
export class ResponseHeaderRemoveInterceptor implements rcp.Interceptor {
  // 自定义响应处理逻辑
  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
    };
    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()
  ],
  requestConfiguration:{
    security:{
      tlsOptions: {
        tlsVersion: 'TlsV1.3'
      }
    }
  }
};

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。

核心代码

// 定义自定义响应处理程序
const customHttpEventsHandler: rcp.HttpEventsHandler = {
  onDataReceive: (incomingData: ArrayBuffer) => {
    // 用于处理传入数据的自定义逻辑
    Logger.info('Received data:', JSON.stringify(incomingData));
    return incomingData.byteLength;
  },
  onHeaderReceive: (headers: rcp.RequestHeaders) => {
    // 处理响应头的自定义逻辑
    Logger.info('Received headers:', JSON.stringify(headers));
  },
  onDataEnd: () => {
    // 用于处理数据传输完成的自定义逻辑
    Logger.info('Data transfer complete');
  }
};

// 配置跟踪设置
const tracingConfig: rcp.TracingConfiguration = {
  verbose: true,
  infoToCollect: {
    incomingHeader: true, // 收集传入的header信息事件
    outgoingHeader: true, // 收集传入的header信息事件
    incomingData: true, // 收集传入数据信息事件
    outgoingData: true // 收集传出数据信息事件
  },
  collectTimeInfo: true,
  httpEventsHandler: customHttpEventsHandler
};
const securityConfig: rcp.SecurityConfiguration = {
  tlsOptions: {
    tlsVersion: 'TlsV1.3'
  }
};
// 创建通信会话对象,并传入相关配置
const session = rcp.createSession({ requestConfiguration: { tracing: tracingConfig, security: securityConfig } });
session.get('http://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请求期间捕获详细的跟踪信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值