引言
為處理大量重復(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)
對(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)需要包含的必要的文件:
- 配置 oh-package.json5 文件,是對(duì)當(dāng)前三方庫的元數(shù)據(jù)描述
- 創(chuàng)建 README 文件,為了幫助其他人在 ohpm 上找到您的三方庫
- 創(chuàng)建 CHANGELOG 文件,描述版本及更新內(nèi)容
- 添加 LICENSE 文件,開源協(xié)議
然后將你的組件編譯生成靜態(tài)包 .har
生成完畢后執(zhí)行命令行進(jìn)行發(fā)布:
ohpm publish xxx.har
(xxx.har
為上傳包的本地路徑)。上傳成功之后,你就可以看到你的個(gè)人中心里面的消息和狀態(tài)了,耐心等待審核。
PS: 組織名申請(qǐng)會(huì)比較耗時(shí)
已開源,附上源碼及Example
- 綜合 Demo 示例已上傳:
- GitHub:https://github.com/liyufengrex/HarmonyAtomicService
- GitCode:https://gitcode.com/liyufengrex/HarmonyAtomicService
(基于API11開發(fā),支持NEXT及以上版本運(yùn)行)已上傳可供參考,包含如下內(nèi)容:
- 靜態(tài)庫+動(dòng)態(tài)包+多模塊設(shè)計(jì)
- 狀態(tài)管理
- 統(tǒng)一路由管理(router+navPathStack)
- 網(wǎng)絡(luò)請(qǐng)求、Loading 等工具庫封裝
- 自定義組件、自定義彈窗(解耦)
- EventBus 事件通知
- 擴(kuò)展修飾器,實(shí)現(xiàn) 節(jié)流、防抖、權(quán)限申請(qǐng)
- 動(dòng)態(tài)路由 (navPathStack + 動(dòng)態(tài)import + WrappedBuilder)
- UI動(dòng)態(tài)節(jié)點(diǎn)操作 (BuilderNode + NodeController)
- 折疊屏適配示例
- 折疊屏適配示例
- 組件工廠示例
- 組件動(dòng)態(tài)屬性設(shè)置示例
- 云函數(shù)、云數(shù)據(jù)庫使用示例
- 華為賬號(hào)服務(wù)示例(快速登陸、快速驗(yàn)證手機(jī)號(hào))