鸿蒙开发-RCP 远程通信请求封装

官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/remote-communication-customdnsconfig

模拟机 / 真机调试遇到的问题

{
    "code": 1007900007,
    "data": "Couldn't connect to server",
    "extendInfo": {
        "httpPhase": "110000",
        "dnsDur": "0.10",
        "tcpDur": "0.00",
        "tlsDur": "0.00",
        "sndDur": "0.00",
        "rcvDur": "0.00",
        "totDur": "0.66",
        "redDur": "0.00",
        "osErr": "111",
        "sptIP6": "0",
        "proxyType": "none",
        "sock": "98",
        "tcpConnE": "115",
        "tryConnV4": "1",
        "tryConnV6": "0"
    }
}

官网描述:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/remote-communication-error-code#section31071676416

说是无法连接到服务器。

原因分析

![](https://cdn.nlark.com/yuque/0/2025/png/27158901/1748878895702-3a7d4c27-356d-49ea-8ff4-cd5ea1564d57.png)

调试时使用的基地址为 localhost:8080,因为我们运行是在 模拟机 或 真机上,所有访问的 localhost:8080 无法映射到电脑的服务端。

解决方案

  1. 可以使用云服务器。
  2. 内网穿透。

因为只是在本地进行测试封装的RCP工具是否可用,所以用云服务器大材小用了。所以这里使用内网穿透。内网穿透有很多的方式。

  1. cpolar。(https://www.cpolar.com/docs
  2. 路由侠。(https://www.luyouxia.com/
  3. 等等。

在这里使用路由侠进行操作。将基地址换成内网穿透后的公网地址即可。

工具封装

目前实现的请求类型有:GET、POST、PUT、DELETE、FETCH。并自定义了请求拦截器和响应拦截器。

import { rcp } from '@kit.RemoteCommunicationKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';

export interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

export class RcpUtil {
  // 基地址
  private static BASE_URL = "http://chen.w1.luyouxia.net";

  // 获取会话
  private static getSession(): rcp.Session {
    // 会话配置
    const sessionConfig: rcp.SessionConfiguration = {
      // 定义拦截器
      interceptors: [
        new RequestInterceptor(),
        new ResponseInterceptor()
      ],
      requestConfiguration: {
        security: {
          tlsOptions: {
            tlsVersion: 'TlsV1.3'
          }
        },
        transfer: {
          timeout: {
            connectMs: 3600,
            transferMs: 6000
          }
        }
      }
    }
    // 创建会话并返回
    return rcp.createSession(sessionConfig);
  }

  // 关闭会话
  private static closeSession(session: rcp.Session) {
    session.close()
  }

  // get 请求处理参数拼接
  private static requestParamHandle(url: string, data: object): string {
    let tempUrl = url
    // data 参数都需要拼接到地址上,如:?a=1&b=2
    if (data && Object.keys(data).length) {
      tempUrl += "?" + Object.keys(data).filter(key => !!data[key]).map(key => `${key}=${data[key]}`).join('&')
    }
    return tempUrl
  }

  // fetch 请求
  public static fetch<T>(path: string, method: rcp.HttpMethod, data?: object): Promise<T> {
    let url = RcpUtil.BASE_URL + path
    if (method === 'GET' && data) {
      // GET 请求需要处理地址拼接
      url = RcpUtil.requestParamHandle(url, data)
    }
    // 创建 request 请求
    const request = new rcp.Request(url, method);
    request.content = method === 'GET' ? '' : data
    // 创建会话
    const session = RcpUtil.getSession();
    // 发起请求
    return new Promise((resolve, reject) => {
      session.fetch(request)
        .then((res: rcp.Response) => {
          const result = res.toJSON() as ApiResponse<T>
          resolve(result?.data)
        })
        .catch((err: BusinessError) => {
          reject(err)
        })
        .finally(() => {
          RcpUtil.closeSession(session) // 关闭会话
        })
    })
  }

  // get 请求
  public static get<T>(path: string, param?: object): Promise<T> {

    let url = RcpUtil.requestParamHandle(RcpUtil.BASE_URL + path, param as object)
    // 创建会话
    const session = RcpUtil.getSession();
    // 发起请求
    return new Promise((resolve, reject) => {
      session.get(url)
        .then((res: rcp.Response) => {
          const result = res.toJSON() as ApiResponse<T>
          resolve(result?.data)
        })
        .catch((err: BusinessError) => {
          reject(err)
        })
        .finally(() => {
          RcpUtil.closeSession(session)
        })
    })
  }

  // post 请求
  public static post<T>(path: string, data?: object): Promise<T> {
    // 定义 content,请根据实际情况选择
    const postContent: rcp.RequestContent = data as object
    // 创建会话
    const session = RcpUtil.getSession();
    // 发起请求
    return new Promise((resolve, reject) => {
      session.post(RcpUtil.BASE_URL + path, postContent)
        .then((res: rcp.Response) => {
          const result = res.toJSON() as ApiResponse<T>
          resolve(result?.data)
        })
        .catch((err: BusinessError) => {
          reject(err)
        })
    })
  }

  // put 请求
  public static put<T>(path: string, data?: object): Promise<T> {
    // 定义 content,请根据实际情况选择
    const putContent: rcp.RequestContent = data as object
    // 创建会话
    const session = RcpUtil.getSession();
    // 发起请求
    return new Promise((resolve, reject) => {
      session.put(RcpUtil.BASE_URL + path, putContent)
        .then((res: rcp.Response) => {
          const result = res.toJSON() as ApiResponse<T>
          resolve(result?.data)
        })
        .catch((err: BusinessError) => {
          reject(err)
        })
    })
  }

  // delete
  public static delete<T>(path: string): Promise<T> {
    // 创建会话
    const session = RcpUtil.getSession();
    // 发起请求
    return new Promise((resolve, reject) => {
      session.delete(RcpUtil.BASE_URL + path)
        .then((res: rcp.Response) => {
          const result = res.toJSON() as ApiResponse<T>
          resolve(result?.data)
        })
        .catch((err: BusinessError) => {
          reject(err)
        })
    })
  }
}


// 定义RequestInterceptor拦截器
class RequestInterceptor implements rcp.Interceptor {
  // 自定义请求处理逻辑
  async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
    if (context.request.headers) {
      context.request.headers.authorization = 'token'
    } else {
      context.request.headers = {
        authorization: 'token',
        "content-type": 'application/json',
      }
    }
    return next.handle(context);
  }
}

// 定义ResponseInterceptor拦截器
class ResponseInterceptor implements rcp.Interceptor {
  // 自定义响应处理逻辑
  async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
    const response = await next.handle(context);
    const result = response.toJSON() as ApiResponse<object>
    console.log("服务端返回结果: " + JSON.stringify(result))
    if (response.statusCode === 200) {
      // 判断业务状态码
      if (result.code === 200) {
        // 成功响应
        return Promise.resolve(response)
      } else {
        // 失败响应
        promptAction.showToast({ message: result?.message })
        // 抛出异常
        return Promise.reject(new Error(result.message))
      }
    } else {
      // 失败响应,比如 401
      // 后端通过 response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); 这种形式返回才会进入
      return Promise.reject(response);
    }
  }
}
posted @ 2025-06-03 00:38  是小陈呀  阅读(157)  评论(0)    收藏  举报