【高心星出品】
RCP框架的使用
Remote Communication Kit中的@hms.collaboration.rcp(后续简称RCP)指的是远程通信平台(remote communication platform),RCP提供了网络数据请求功能,相较于Network Kit中HTTP请求能力,RCP更具易用性,且拥有更多的功能。在开发过程中,如果有些场景使用Network Kit中HTTP请求能力达不到预期或无法实现,那么就可以尝试使用RCP中的数据请求功能来实现。
RCP vs 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.Request
let req = new rcp.Request(url: URLOrString, method?: HttpMethod, headers?: RequestHeaders, content?: RequestContent, cookies?: RequestCookies, transferRange?: TransferRange | TransferRange[], configuration?: Configuration)
参数名 | 类型 | 必填 | 说明 | |
---|---|---|---|---|
url | URLOrString | 是 | 请求的地址类型,在构造函数中,参数可以是 URLOrString,但 URL 只是 URL,字符串需要转换为URL。 | |
method | HttpMethod | 否 | HTTP 请求方法。默认是GET。 | |
headers | RequestHeaders | 否 | HTTP请求头。 | |
content | RequestContent | 否 | HTTP 请求正文。 | |
cookies | RequestCookies | 否 | HTTP 请求 cookie。该设置将转换为 HTTP Cookies header。 | |
transferRange | TransferRange\ | TransferRange[] | 否 | HTTP 传输范围。该设置将转换为 HTTP Range header。常用于断点续传。 |
configuration | Configuration | 否 | HTTP 请求配置。见Configuration。 |
应答对象rcp.Response
名称 | 类型 | 只读 | 必填 | 说明 |
---|---|---|---|---|
request | Request | 是 | N/A | 收到此响应的相关HTTP请求内容。 |
statusCode | number | 是 | N/A | HTTP请求的结果代码。如果回调函数成功执行,将返回ResponseCode中定义的结果代码。否则,将在AsyncCallback中的error字段中返回错误代码。 |
headers | ResponseHeaders | 是 | N/A | 响应头。 |
effectiveUrl | URL | 是 | N/A | 重定向后请求的有效URL。默认值为undefined。 |
body | ArrayBuffer | 是 | N/A | 响应内容根据响应头中的Content-type返回。响应内容必须与服务器返回的数据类型相同。 |
downloadedTo | DownloadedTo | 是 | N/A | 内容下载的路径。在使用下载至文件对象和文件标识符两种方式时,默认情况下,并未设置回调信息。起始版本:5.0.0(12) |
debugInfo | DebugInfo[] | 是 | N/A | 与响应相关联的调试信息。默认值为undefined。 |
timeInfo | TimeInfo | 是 | N/A | HTTP请求各阶段的定时信息。默认值为undefined。 |
cookies | ResponseCookie[] | 是 | N/A | 响应中的Cookie数组。 |
httpVersion | HttpVersion | 是 | N/A | HTTP的版本。起始版本:5.0.0(12) |
reasonPhrase | string | 是 | N/A | HTTP响应状态行的reasonPhrase,提供与数字状态代码相关的文本描述。起始版本:5.0.0(12) |
toString() | 方法 | 否 | N/A | 将应答结果转化为字符串,主要是转化了body的结果 |
toJson() | 方法 | 否 | N/A | 将toString()方法返回的字符串转化为json对象,我们可以进一步处理成自己需要的类型。 |
简单的应用
该测试应用包含了基本发送get、post请求,编写请求和应答拦截器、下载文件、下载文件流、上传文件、上传文件流等功能的实现。通过编写该案例可以覆盖大部分RCP框架的应用场景。
Get请求
- 创建会话对象
- 创建请求对象
- 发起请求
let sessionconfig: rcp.SessionConfiguration = {
//请求服务器基准地址
baseAddress: 'https://httpbin.org'
}
let session = rcp.createSession(sessionconfig) //创建会话
let req = new rcp.Request('/get?id=10&name=gxx', 'GET') //创建get请求
session.fetch(req).then((res: rcp.Response) => { //发送请求获取应答
this.message = JSON.stringify(res)
}).catch((e: Error) => {
this.message = 'gxxt ' + e.message
}).finally(() => {
session.close() //关闭会话
})
Post请求
- 创建会话对象
- 创建请求对象
- 发起请求
let userinfo: UserType = {
//post请求携带数据
id: '10',
name: 'gxx'
}
let sessionconfig: rcp.SessionConfiguration = {
//会话配置项
baseAddress: 'https://httpbin.org'
}
let session = rcp.createSession(sessionconfig) //创建会话
let req = new rcp.Request('/post', 'POST', undefined, userinfo) //创建请求
session.fetch(req).then((res: rcp.Response) => { //发送请求获得应答
this.message = 'gxxt ' + JSON.stringify(res)
}).catch((e: Error) => {
this.message = 'gxxt ' + e.message
}).finally(() => {
session.close() //关闭会话
})
使用拦截器
- 自定义拦截器
拦截器需要实现rcp.Interceptor接口并重写interceptor方法。
async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response>
context:包含了请求对象和会话对象,可以获取请求的信息。
next:请求执行器,可以执行context获取应答结果。
Promise<rcp.Response>:返回一个应答结果,可以是next执行的结果也可以是自己创建的应答结果。
下面案例定义一个拦截器,将请求中携带数据修改,并拦截应答结果,只返回部分应答结果。
export class HttpReqInterceptor implements rcp.Interceptor {
// 拦截方法
//context 包含所有的请求和会话信息
//next 下一个拦截器
async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
let url = context.request.url
if (url.hostname === 'httpbin.org' && url.params.has('id') && context.request.method === 'GET') { //判定地址中半酣httpbin并且携带数据有id
let id = url.params.get('id')
url.params.set('id', 'id-' + id) //将id的值替换为id-
}
let res=await next.handle(context) //获取应答数据
let nres:rcp.Response={ //在应答数据的基础上创建了新的应答数据
request:res.request,
headers:res.headers,
statusCode:res.statusCode,
// 将返回的数据进行了截取只获取args的值
toJSON:()=> JSON.parse(res.toString()!.substring(res.toString()!.indexOf(':')+1,res.toString()!.indexOf('}')+1).replace('\n',''))
}
return nres //返回了新的应答数据
}
}
- 创建会话对象
- 创建请求对象
- 发起请求
let sessionconfig: rcp.SessionConfiguration = {
//请求服务器基准地址
baseAddress: 'https://httpbin.org',
interceptors: [//使用自定义的拦截器
new HttpReqInterceptor()
]
}
let session = rcp.createSession(sessionconfig) //创建会话
let req = new rcp.Request('/get?id=10&name=gxx', 'GET') //创建get请求
session.fetch(req).then((res: rcp.Response) => { //发送请求获取应答
this.message = 'gxxt ' + (res.toJSON() as UserType).name//将应答结果转化为自己定义的类型
}).catch((e: Error) => {
this.message = 'gxxt ' + e.message
}).finally(() => {
session.close() //关闭会话
})
下载文件
- 创建文件保存位置
// 文件保存位置
let downloadfile: rcp.DownloadToFile = {
kind: 'folder', //目录类型
path: getContext(this).filesDir //目录的路径
}
- 创建会话对象
- 下载文件
// 图片资源地址
let url =
'https://ts1.cn.mm.bing.net/th/id/R-C.57384e4c2dd256a755578f00845e60af?rik=uy9%2bvT4%2b7Rur%2fA&riu=http%3a%2f%2fimg06file.tooopen.com%2fimages%2f20171224%2ftooopen_sy_231021357463.jpg&ehk=whpCWn%2byPBvtGi1%2boY1sEBq%2frEUaP6w2N5bnBQsLWdo%3d&risl=&pid=ImgRaw&r=0'
// 会话对象
let session: rcp.Session = rcp.createSession()
// 文件保存位置
let downloadfile: rcp.DownloadToFile = {
kind: 'folder',
path: getContext(this).filesDir
}
// 开始下载文件
session.downloadToFile(url, downloadfile).then((res) => {
this.message = 'gxxt a' + JSON.stringify(res)
}).catch((e: Error) => {
this.message = 'gxxt ' + e.message
}).finally(() => {
session.close()
})
下载文件流
- 创建文件写流
let downloadto: rcp.DownloadToStream = {
kind: 'stream', //类型为流
stream: {
write: (buffer: ArrayBuffer) => { //每次下载的资源保存在buffer中,会执行多次
let len= fileIo.writeSync(f.fd, buffer) //写入到文件中
return Promise.resolve(len) //返回写入文件的字节个数
}
}
}
- 创建会话对象
- 读取网络资源的字节流
将该字节流保存在设备上
// 图片资源地址 let url = 'https://ts1.cn.mm.bing.net/th/id/R-C.57384e4c2dd256a755578f00845e60af?rik=uy9%2bvT4%2b7Rur%2fA&riu=http%3a%2f%2fimg06file.tooopen.com%2fimages%2f20171224%2ftooopen_sy_231021357463.jpg&ehk=whpCWn%2byPBvtGi1%2boY1sEBq%2frEUaP6w2N5bnBQsLWdo%3d&risl=&pid=ImgRaw&r=0' let session: rcp.Session = rcp.createSession() //会话对象 let file = getContext(this).filesDir + '/test2.jpg' //文件保存路径 let f: fileIo.File = fileIo.openSync(file, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY) //文件对象 let downloadto: rcp.DownloadToStream = { kind: 'stream', stream: { write: (buffer: ArrayBuffer) => { //每次下载的资源保存在buffer中,会执行多次 let len= fileIo.writeSync(f.fd, buffer) //写入到文件中 return Promise.resolve(len) //返回写入文件的字节个数 } } } session.downloadToStream(url, downloadto).then((res: rcp.Response) => { //下载文件成字节流 this.message = 'gxxt downloadtostream ' + JSON.stringify(res) }).catch((e: Error) => { this.message = 'gxxt ' + e.message }).finally(() => { session.close() })
上传文件
- 要上传的文件对象
// 文件地址
let uploadfromfile: rcp.UploadFromFile = {
fileOrPath: getContext(this).filesDir + '/test1.jpg'
}
- 创建会话对象
- 上传文件请求
// 上传地址
let url = 'https://httpbin.org/post'
// 会话对象
let session = rcp.createSession()
// 文件地址
let uploadfromfile: rcp.UploadFromFile = {
fileOrPath: getContext(this).filesDir + '/test1.jpg'
}
// 开始上传
session.uploadFromFile(url, uploadfromfile).then((res: rcp.Response) => {
this.message = 'gxxt ' + JSON.stringify(res)
}).catch((e: Error) => {
this.message = 'gxxt ' + e.message
}).finally(() => {
session.close()
})
上传文件流
- 要上传文件对象读流
let uploadstream: rcp.UploadFromStream = {
stream: {
read: (buffer: ArrayBuffer) => { //每次将文件的字节读入buffer 等待上传到服务器
let len = fileIo.readSync(file.fd, buffer)
console.log('gxxt 读了:', len)
return Promise.resolve(len)
}
}
}
- 创建会话对象
- 上传文件对象流
// 文件上传地址
let url = 'https://httpbin.org/post'
// 创建会话对象
let session = rcp.createSession()
// 需要上传的文件
let file: fileIo.File = fileIo.openSync(getContext(this).filesDir + '/test1.jpg', fileIo.OpenMode.READ_ONLY)
let uploadstream: rcp.UploadFromStream = {
stream: {
read: (buffer: ArrayBuffer) => { //每次将文件的字节读入buffer 等待上传到服务器
let len = fileIo.readSync(file.fd, buffer)
console.log('gxxt 读了:', len)
return Promise.resolve(len)
}
}
}
session.uploadFromStream(url, uploadstream).then((res: rcp.Response) => { //开始上传
this.message = 'gxxt ' + JSON.stringify(res)
}).catch((e: Error) => {
this.message = 'gxxt ' + e.message
}).finally(() => {
session.close()
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。