鴻蒙運動項目開發(fā):封裝超級好用的 RCP 網(wǎng)絡(luò)庫(下)—— 實戰(zhàn)應(yīng)用

鴻蒙核心技術(shù)##運動開發(fā)## Remote Communication Kit(遠場通信服務(wù))

在之前的文章中,我們詳細介紹了如何封裝一個功能完備的 RCP 網(wǎng)絡(luò)庫,并探討了其核心功能和高級特性。在本篇中,我們將展示如何在鴻蒙運動項目中使用這個網(wǎng)絡(luò)庫來實現(xiàn)具體的網(wǎng)絡(luò)請求功能。

前言

在鴻蒙運動項目中,網(wǎng)絡(luò)請求是實現(xiàn)功能的關(guān)鍵環(huán)節(jié)之一。無論是獲取運動數(shù)據(jù)、同步用戶信息,還是加載運動視頻資源,都需要一個穩(wěn)定、高效且易于使用的網(wǎng)絡(luò)庫。在本篇中,我們將通過實際代碼樣例,展示如何使用封裝好的 RCP 網(wǎng)絡(luò)庫實現(xiàn)這些功能。

一、封裝異常處理

在實際開發(fā)中,異常處理是網(wǎng)絡(luò)請求中不可或缺的一部分。通過自定義異常類,我們可以更好地管理網(wǎng)絡(luò)請求中可能出現(xiàn)的各種錯誤。

(一)自定義異常類

定義了一個 ApiException 類,用于封裝 API 請求中的錯誤信息。

export class ApiException extends Error {
  apiCode?: number;
  apiMessage?: string;

  constructor(apiCode?: number, apiMessage?: string) {
    super();
    this.name = "ApiException";
    this.apiCode = apiCode;
    this.apiMessage = apiMessage;
  }
}

核心點解析

  1. 自定義屬性apiCodeapiMessage 用于存儲 API 返回的錯誤代碼和錯誤信息。
  2. 構(gòu)造函數(shù):通過構(gòu)造函數(shù)初始化異常對象,并設(shè)置錯誤代碼和錯誤信息。

二、封裝網(wǎng)絡(luò)請求

為了簡化網(wǎng)絡(luò)請求的實現(xiàn),你封裝了一個 ApiRequest 類,用于統(tǒng)一管理網(wǎng)絡(luò)請求和錯誤處理。

(一)單例模式

ApiRequest 類使用了單例模式,確保全局只有一個實例。


import { DataResult, ErrorCodes, ErrorData, LibToast, NetworkException, SuccessData } from "lib_base";
import { RcpNetworkService } from "lib_base/src/main/ets/utils/rcpnet/RcpService";
import { ApiResult } from "../data/models/ApiResult";
import { ApiException } from "./ApiException";

export interface IApiRequestHandleBusinessError{
  handleBusinessError(apiException: ApiException): boolean
}

export class ApiRequest{

  private static instance: ApiRequest


  static getInstance (): ApiRequest {
    if (!ApiRequest.instance) {
      ApiRequest.instance = new ApiRequest()
    }
    return ApiRequest.instance
  }

  private _net?: RcpNetworkService | undefined;
  private _i_api_equest_handle_business_error?: IApiRequestHandleBusinessError | undefined;

  public set i_api_equest_handle_business_error(value: IApiRequestHandleBusinessError | undefined) {
    this._i_api_equest_handle_business_error = value;
  }

  public set net(value: RcpNetworkService | undefined) {
    this._net = value;
  }

  public getService() : RcpNetworkService{
    return this._net!;
  }


  

}

核心點解析

  1. 單例模式:通過 getInstance 方法確保 ApiRequest 的全局唯一性。
  2. 依賴注入:通過 set 方法注入 RcpNetworkServiceIApiRequestHandleBusinessError,增強類的靈活性。

(二)統(tǒng)一請求方法

ApiRequest 類提供了一個統(tǒng)一的請求方法 remoteApi,用于處理網(wǎng)絡(luò)請求并封裝返回結(jié)果。

export interface IApiRequestHandleBusinessError {
  handleBusinessError(apiException: ApiException): boolean;
}

export class ApiRequest {
  
  public static async remoteApi<T>(api:()=>Promise<ApiResult<T>>): Promise<DataResult<ApiResult<T>|null>>{
    try{
      const data = await api()
      if(data.success && data.success){
        let bean = new SuccessData<ApiResult<T>>(data)
        return bean;
      } else {
        let bean = ErrorData.fromError(new ApiException(data.code,data.msg) as Error,data.code?.toString(),data.msg)
        return bean;
      }
    }catch (e) {
      if(e instanceof NetworkException){
        let bean = ErrorData.fromError(e)
        //請求被框架取消,客戶端不進入異常處理,避免業(yè)務(wù)彈窗
        if(e.code !== ErrorCodes.REQUEST_CANCEL){
          LibToast.show(e.message)
        }
        return bean;
      }
      throw e as Error
    }

  }
}

核心點解析

  1. 請求執(zhí)行:通過傳入的 api 函數(shù)執(zhí)行具體的網(wǎng)絡(luò)請求。
  2. 成功處理:如果請求成功,返回 SuccessData 對象。
  3. 失敗處理:如果請求失敗,根據(jù)錯誤類型返回 ErrorData 對象。
  4. 網(wǎng)絡(luò)異常處理:捕獲 NetworkException,并根據(jù)錯誤代碼決定是否顯示提示信息。

(三)業(yè)務(wù)邏輯處理

ApiRequest 類還提供了一個 service 方法,用于處理業(yè)務(wù)邏輯和錯誤。

export class ApiRequest {
  // ... 其他代碼 ...

  public static async service<T>(source:()=>Promise<DataResult<ApiResult<T>|null>>,
    request : (data:DataResult<T|null>)=>void,
    apiError : (apiError:ErrorData)=>void,
    netError? : (netError:ErrorData)=>void,
  ){
    let data = await source();
    if(data instanceof SuccessData){
      request(data.data)
    }else {
      let error = data as ErrorData
      if(error.error&&error.error instanceof ApiException){
        //業(yè)務(wù)異常
        if(ApiRequest.instance._i_api_equest_handle_business_error){
          ApiRequest.instance._i_api_equest_handle_business_error.handleBusinessError(error.error)
        }
        apiError(error)
      }else {
        //網(wǎng)絡(luò)異常
        if(netError){
          netError(error)
        }
      }
    }
  }
}

核心點解析

  1. 請求執(zhí)行:通過 source 函數(shù)執(zhí)行網(wǎng)絡(luò)請求。
  2. 成功處理:如果請求成功,調(diào)用 request 回調(diào)函數(shù)處理數(shù)據(jù)。
  3. 錯誤處理:根據(jù)錯誤類型調(diào)用 apiErrornetError 回調(diào)函數(shù)。
  4. 業(yè)務(wù)邏輯分離:通過 IApiRequestHandleBusinessError 接口處理業(yè)務(wù)邏輯錯誤。

三、封裝公共請求頭

在實際開發(fā)中,許多請求都需要攜帶公共請求頭,例如設(shè)備信息、用戶令牌等。你通過 CommonHeaderInterceptor 類實現(xiàn)了公共請求頭的封裝。

export async function getCommonHeaders(): Promise<Record<string, string>> {
  return {
    "device": LibDevice.getDeviceInfo(),
    "machineCode": await USystem.getUniqueKey(),
    "terminalType": "1", // 示例終端類型
    "timestamp": new Date().toISOString(),
    "versionNumber": LibDevice.getAppVersionCode().toString(),
    "osId": Platform.appPlatform, // 示例 osId
    "versionCode": LibDevice.getAppVersionName(),
    "token": AccountManager.getToken()
  };
}

export class CommonHeaderInterceptor implements rcp.Interceptor {
  async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
    const commonHeaders = await getCommonHeaders();
    const keys = Object.keys(commonHeaders);
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      if (!context.request.headers) {
        context.request.headers = {};
      }
      context.request.headers[key] = commonHeaders[key];
    }
    return next.handle(context);
  }
}

核心點解析

  1. 公共頭信息:通過 getCommonHeaders 函數(shù)獲取公共頭信息。
  2. 攔截器實現(xiàn):在 intercept 方法中,將公共頭信息添加到請求頭中。
  3. 動態(tài)添加:通過循環(huán)動態(tài)添加公共頭信息,確保每個請求都攜帶必要的信息。

四、封裝響應(yīng)轉(zhuǎn)換器

為了更好地處理響應(yīng)數(shù)據(jù),封裝一個 CommonTextResponseConverter 類,用于處理響應(yīng)內(nèi)容。

export class CommonTextResponseConverter extends TextResponseConverter {
  convert(response: rcp.Response): string | object | null {
    if (response.toJSON()) {
      return response.toJSON();
    } else {
      return super.convert(response);
    }
  }
}

核心點解析

  1. JSON 轉(zhuǎn)換:優(yōu)先嘗試將響應(yīng)內(nèi)容轉(zhuǎn)換為 JSON 格式。
  2. 回退處理:如果無法轉(zhuǎn)換為 JSON,調(diào)用父類的 convert 方法處理響應(yīng)內(nèi)容。

五、實際應(yīng)用案例:獲取運動數(shù)據(jù)

假設(shè)我們需要從服務(wù)器獲取用戶的運動數(shù)據(jù),例如運動記錄、運動計劃等。我們將通過封裝好的 RCP 網(wǎng)絡(luò)庫來實現(xiàn)這一功能。

(一)封裝請求方法

export async function getAllLookSubjectList(params: Record<"parentId", string>, requestKeyFun?: (str: string) => void): Promise<ApiResult<Subject[]>> {
  return ApiRequest.getInstance().getService().request<ApiResult<Subject[]>>>({
    act: AllLOOK_SUBJECT_LIST,
    method: RequestMethod.POST,
    contentType: RcpContentType.JSON,
    content: params
  }, requestKeyFun);
}

核心點解析

  1. 請求配置:通過 RequestOptions 配置請求的基本信息,如 API 路徑、請求方法和內(nèi)容類型。
  2. 請求發(fā)送:使用 ApiRequest.getInstance().getService().request 方法發(fā)送請求。
  3. 回調(diào)函數(shù):通過 requestKeyFun 提供請求鍵值,用于取消請求等操作。

(二)調(diào)用請求方法

在實際的頁面或組件中,我們可以調(diào)用封裝好的請求方法來獲取運動數(shù)據(jù)。

aboutToAppear(): void {
  super.aboutToAppear();
  this.showLoading();
  ApiRequest.service<Subject[]>(() => {
    return LookResponsitory.getInstance().getAllLookSubjectList("1", (requestKey) => {
      if (requestKey) {
        this.addRequestId(requestKey);
      }
    });
  }, (data) => {
    this.hideLoading();
    if (data.data && data.data.length > 0) {
      this.tabs = data.data;
    } else {
      this.setDefalutTab();
    }
  }, (apiError) => {
    this.hideLoading();
    this.setDefalutTab();
    // 業(yè)務(wù)異常
    // LibToast.show(apiError.message ?? "獲取異常");
  }, () => {
    this.hideLoading();
    this.setDefalutTab();
    // 網(wǎng)絡(luò)等異常
    // LibToast.show("網(wǎng)絡(luò)異常");
  });
}

核心點解析

  1. 請求執(zhí)行:通過 ApiRequest.service 方法執(zhí)行網(wǎng)絡(luò)請求。
  2. 成功處理:如果請求成功,處理返回的數(shù)據(jù)。
  3. 錯誤處理:根據(jù)錯誤類型調(diào)用相應(yīng)的回調(diào)函數(shù)處理錯誤。
  4. 加載狀態(tài):在請求開始時顯示加載狀態(tài),在請求結(jié)束時隱藏加載狀態(tài)。

六、總結(jié)

通過本篇的實戰(zhàn)案例,我們展示了如何使用封裝好的 RCP 網(wǎng)絡(luò)庫實現(xiàn)具體的網(wǎng)絡(luò)請求功能。通過定義異常類、封裝請求方法、處理公共請求頭和響應(yīng)轉(zhuǎn)換器,以及實現(xiàn)具體的請求邏輯,我們能夠高效地完成網(wǎng)絡(luò)請求任務(wù)。封裝好的網(wǎng)絡(luò)庫不僅提供了基本的請求和響應(yīng)處理功能,還具備錯誤處理、日志記錄、會話管理和網(wǎng)絡(luò)狀態(tài)檢測等高級特性,能夠滿足大多數(shù)網(wǎng)絡(luò)請求場景的需求。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容