HarmonyOS :面向?qū)ο笫骄W(wǎng)絡(luò)請(qǐng)求庫,我發(fā)布的第一個(gè)鴻蒙三方庫

引言

為處理大量重復(fù)的代碼邏輯,基于 http 封裝的一套面向?qū)ο笫降木W(wǎng)絡(luò)請(qǐng)求庫,支持將請(qǐng)求返回的數(shù)據(jù)直接轉(zhuǎn)換成指定類型的對(duì)象。本篇記錄封裝前后的使用對(duì)比,以及在鴻蒙ohpm發(fā)布三方庫的操作記錄。

官網(wǎng)的 http 案例

如下代碼,是官方給出的請(qǐng)求案例:

// 引入包名
import http from '@ohos.net.http';

// 每一個(gè)httpRequest對(duì)應(yīng)一個(gè)HTTP請(qǐng)求任務(wù),不可復(fù)用
let httpRequest = http.createHttp();
// 用于訂閱HTTP響應(yīng)頭,此接口會(huì)比request請(qǐng)求先返回。可以根據(jù)業(yè)務(wù)需要訂閱此消息
// 從API 8開始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。 8+
httpRequest.on('headersReceive', (header) => {
    console.info('header: ' + JSON.stringify(header));
});
httpRequest.request(
    // 填寫HTTP請(qǐng)求的URL地址,可以帶參數(shù)也可以不帶參數(shù)。URL地址需要開發(fā)者自定義。請(qǐng)求的參數(shù)可以在extraData中指定
    "EXAMPLE_URL",
    {
        method: http.RequestMethod.POST, // 可選,默認(rèn)為http.RequestMethod.GET
        // 開發(fā)者根據(jù)自身業(yè)務(wù)需要添加header字段
        header: {
            'Content-Type': 'application/json'
        },
        // 當(dāng)使用POST請(qǐng)求時(shí)此字段用于傳遞內(nèi)容
        extraData: {
            "data": "data to send",
        },
        expectDataType: http.HttpDataType.STRING, // 可選,指定返回?cái)?shù)據(jù)的類型
        usingCache: true, // 可選,默認(rèn)為true
        priority: 1, // 可選,默認(rèn)為1
        connectTimeout: 60000, // 可選,默認(rèn)為60000ms
        readTimeout: 60000, // 可選,默認(rèn)為60000ms
        usingProtocol: http.HttpProtocol.HTTP1_1, // 可選,協(xié)議類型默認(rèn)值由系統(tǒng)自動(dòng)指定
    }, (err, data) => {
        if (!err) {
            // data.result為HTTP響應(yīng)內(nèi)容,可根據(jù)業(yè)務(wù)需要進(jìn)行解析
            console.info('Result:' + JSON.stringify(data.result));
            console.info('code:' + JSON.stringify(data.responseCode));
            // data.header為HTTP響應(yīng)頭,可根據(jù)業(yè)務(wù)需要進(jìn)行解析
            console.info('header:' + JSON.stringify(data.header));
            console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
            // 取消訂閱HTTP響應(yīng)頭事件
            httpRequest.off('headersReceive');
            // 當(dāng)該請(qǐng)求使用完畢時(shí),調(diào)用destroy方法主動(dòng)銷毀
            httpRequest.destroy();
        } else {
            console.info('error:' + JSON.stringify(err));
            // 取消訂閱HTTP響應(yīng)頭事件
            httpRequest.off('headersReceive');
            // 當(dāng)該請(qǐng)求使用完畢時(shí),調(diào)用destroy方法主動(dòng)銷毀。
            httpRequest.destroy();
        }
    }
);

可以看到,上述請(qǐng)求的代碼量龐大,在實(shí)際開發(fā)中,我們需要將公共的部分進(jìn)行抽取封裝,將可變的參數(shù)暴露到上層進(jìn)行動(dòng)態(tài)填充或者重寫,達(dá)到簡(jiǎn)化請(qǐng)求代碼的目標(biāo)。

fast_http,一個(gè)簡(jiǎn)易面向?qū)ο笫降木W(wǎng)絡(luò)庫

1. 安裝

ohpm install @rex/fast_https_request

2. 導(dǎo)入引用

import { http } from '@kit.NetworkKit'
import { HttpRequest } from '@rex/fast_https_request/Index';

3. 定義通用數(shù)據(jù)模型

首先,我們定義一個(gè)常規(guī)返回?cái)?shù)據(jù)模型,比如這樣的JSON結(jié)構(gòu):

{
    'code': 100
    'data': {
        // 里面是具體的業(yè)務(wù)模型
    }
}

對(duì)應(yīng)的模型我們定義如下:

/// 接口返回結(jié)果通用模型, 泛型T為具體的業(yè)務(wù)模型對(duì)象
interface CommonResponseModel<T> {
  code: number
  data: T
}

4. 定義業(yè)務(wù)數(shù)據(jù)模型

定義具體的業(yè)務(wù)數(shù)據(jù)模型,也就是上述 CommponResponseModel 里的 T 泛型,例如這樣

/// 具體的業(yè)務(wù)模型
class ResponseModel {
  artistsname: string
  name: string
  picurl: string
  url: string

  constructor(
    artistsname: string,
    name: string, picurl:
    string, url: string
  ) {
    this.artistsname = artistsname
    this.name = name
    this.picurl = picurl
    this.url = url
  }
}

5. 創(chuàng)建網(wǎng)絡(luò)請(qǐng)求

聲明網(wǎng)絡(luò)請(qǐng)求,指定將返回結(jié)果直接轉(zhuǎn)換成上面的業(yè)務(wù)模型,我們這么做:

  • 如果是GET請(qǐng)求,這么寫
// HttpRequest<T> 將response的返回?cái)?shù)據(jù)直接轉(zhuǎn)成指定的泛型
class GetRequest extends HttpRequest<CommonResponseModel<ResponseModel>> {
  // 重寫請(qǐng)求類型,默認(rèn)是 POST
  public method: http.RequestMethod = http.RequestMethod.GET;
  // 重寫域名domain
  public domain: string = 'https://api.uomg.com';
  // 重寫請(qǐng)求路徑
  public path: string = '/api/rand.music';
  // GET 傳參賦值
  public getQuery: Record<string, string> = {
    'sort': '熱歌榜',
    'format': 'json',
  }
}
  • 如果是POST請(qǐng)求,這么寫
class PostRequest extends HttpRequest<CommonResponseModel<ResponseModel>> {
  // 重寫請(qǐng)求類型,默認(rèn)是 POST
  public method: http.RequestMethod = http.RequestMethod.POST;
  // 重寫域名domain
  public domain: string = 'https://api.uomg.com';
  // 重寫請(qǐng)求路徑
  public path: string = '/api/comments.163';
  // POST 傳參賦值
  public postBody: Record<string, string> = {
    'format': 'json',
  }
}

6. 發(fā)送網(wǎng)絡(luò)請(qǐng)求

try {
      const response : CommonResponseModel<ResponseModel> = await new GetRequest().execute()
      let responseTxt = JSON.stringify(response);
      console.log(`response == ${responseTxt}`)
    } catch (e) {
      let errorMessage = JSON.stringify(e);
      console.log(`error == ${errorMessage}`)
    }

使用上面聲明的請(qǐng)求 new GetRequest().excute() 或者 new PostRequest().excute() 獲取到的結(jié)果為 CommonResponseModel<ResponseModel> 對(duì)象

let data : ResponseModel = await new GetRequest().execute().data   

這樣就獲取到了我們的業(yè)務(wù)模型對(duì)象

7. 如何打印網(wǎng)絡(luò)日志

在繼承 HttpRequest 時(shí)選擇重寫內(nèi)部三方方法,可用于分別打印 request、response、httpError

class PostRequest extends HttpRequest<T> {
  ....省略具體的請(qǐng)求
  
  // 重寫該方法打印 request
  protected onRequestChain(request: BaseRequestOption): void {
    console.log(`fast_http_request >>> url : ${this.requestUrl()}`)
    if (request.postBody != null){
      console.log(`fast_http_request >>> POST Parmas : ${JSON.stringify(request.postBody)}`)
    }
  }

  // 重寫該方法打印 response
  protected onResponseChain(response: HttpResponse): void {
    console.log(`fast_http_request >>> response : ${JSON.stringify(response)}`)
  }

  // 重寫該方法打印 http error
  protected onErrorChain(error: Error): void {
    console.log(`fast_http_request >>> error : ${JSON.stringify(error)}`)
  }
}

8. 如何在工程中,統(tǒng)一管理,進(jìn)行復(fù)用

我們可以按照域名定義一個(gè)通用的 CommonRequest,例如:

class CommonRequest<T> extends HttpRequest<CommonResponseModel<T>> {
  // 重寫域名domain
  public domain: string = 'https://api.uomg.com';
  
  ///這里自己把log加上,統(tǒng)一打印請(qǐng)求日志
}

遇到具體的業(yè)務(wù)時(shí)

假設(shè)我們業(yè)務(wù)接口返回的的數(shù)據(jù),定義模型名稱為 BusinessModel

class BusinessModel {
    /// 具體的業(yè)務(wù)字段
}

所有的業(yè)務(wù)請(qǐng)求,我們可以通過繼承 CommonRequest,創(chuàng)建具體的業(yè)務(wù)請(qǐng)求,指定泛型即可

class BusinessRequest extends CommonRequest<BusinessModel> {
    // Model 是請(qǐng)求參數(shù),這里我定義為 Record 類型,按照自己的需要也可以定義為其他
    constructor(requestParams: Record<string, Object>){
        this.postBody = requestParams;
    }
    
    // 重寫請(qǐng)求路徑
  public path: string = '具體的url';
}

如上便完成了一個(gè)業(yè)務(wù)請(qǐng)求的封裝, 通過 new 即可使用

let requestParams = {
    'pageIndex': '1',
    'keywords': 'rex',
}

let request = new BusinessRequest(requestParams);

request.excute().then((data)=>{
    // 這里獲取的 data 類型為 CommonResponseModel<BusinessModel>
})

聊一下怎么發(fā)布到鴻蒙三方庫市場(chǎng)

1. 創(chuàng)建組織

先到 OpenHarmony三方庫中心倉 上面注冊(cè)個(gè)賬號(hào),到 個(gè)人中心 ->組織管理 中,申請(qǐng)一個(gè)組織。這個(gè)組織名字以后要用到,因?yàn)槠胀ㄈ阶髡撸遣荒苁褂?ohos 前綴的。

比如我注冊(cè)的是組織名為 rex,組件為 fast_https_request。那么組件最終的名字就是 @rex/fast_https_request

最后用戶可以通過 ohpm install @candies/fast_https_request,來安裝使用組件。

2. 創(chuàng)建項(xiàng)目(選擇靜態(tài)庫)

創(chuàng)建項(xiàng)目,選擇靜態(tài)庫(Static Libray)

image.png

對(duì)應(yīng)的 oh_package.json5 文件里配置的是組件的相關(guān)信息

其他字段,請(qǐng)查看 OpenHarmony三方庫中心倉

3. 發(fā)布

在準(zhǔn)備發(fā)布之前,請(qǐng)先閱讀 貢獻(xiàn)三方庫 里面內(nèi)容。

這里簡(jiǎn)單說一下組件內(nèi)需要包含的必要的文件:

    1. 配置 oh-package.json5 文件,是對(duì)當(dāng)前三方庫的元數(shù)據(jù)描述
    1. 創(chuàng)建 README 文件,為了幫助其他人在 ohpm 上找到您的三方庫
    1. 創(chuàng)建 CHANGELOG 文件,描述版本及更新內(nèi)容
    1. 添加 LICENSE 文件,開源協(xié)議

然后將你的組件編譯生成靜態(tài)包 .har

image.png

生成完畢后執(zhí)行命令行進(jìn)行發(fā)布:

ohpm publish xxx.har

(xxx.har 為上傳包的本地路徑)。上傳成功之后,你就可以看到你的個(gè)人中心里面的消息和狀態(tài)了,耐心等待審核。

image.png

PS: 組織名申請(qǐng)會(huì)比較耗時(shí)

已開源,附上源碼及Example

(基于API11開發(fā),支持NEXT及以上版本運(yùn)行)已上傳可供參考,包含如下內(nèi)容:

    1. 靜態(tài)庫+動(dòng)態(tài)包+多模塊設(shè)計(jì)
    1. 狀態(tài)管理
    1. 統(tǒng)一路由管理(router+navPathStack)
    1. 網(wǎng)絡(luò)請(qǐng)求、Loading 等工具庫封裝
    1. 自定義組件、自定義彈窗(解耦)
    1. EventBus 事件通知
    1. 擴(kuò)展修飾器,實(shí)現(xiàn) 節(jié)流、防抖、權(quán)限申請(qǐng)
    1. 動(dòng)態(tài)路由 (navPathStack + 動(dòng)態(tài)import + WrappedBuilder)
    1. UI動(dòng)態(tài)節(jié)點(diǎn)操作 (BuilderNode + NodeController)
    1. 折疊屏適配示例
    1. 折疊屏適配示例
    1. 組件工廠示例
    1. 組件動(dòng)態(tài)屬性設(shè)置示例
    1. 云函數(shù)、云數(shù)據(jù)庫使用示例
    1. 華為賬號(hào)服務(wù)示例(快速登陸、快速驗(yàn)證手機(jī)號(hào))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容