HarmonyOS 鸿蒙Next基于axios和Promise的网络框架封装
HarmonyOS 鸿蒙Next基于axios和Promise的网络框架封装
基于 axios 和 Promise 的网络框架封装 DevEco Studio 版本:DevEco Studio NEXT
HarmonyOS API 版本:5.0.0(12)
axios 版本:2.2.0
Get Post 方式支持 http 其他请求方式(method)支持 接口 url 参数封装 和 全局的 baseUrl 设置 超时时间设置 全局 Headers,接口自定义 Headers 和 请求 headers 拦截器封装和实现 请求 params 参数和 data 数据支持 post 支持 x-www-form-urlencoded 数据格式 请求结果 Json 数据解析(框架已自动解析) 请求结果流程控制,Promise 封装 请求结果 header 数据解析,服务器时间戳和 session 关键代码 HttpUtil.ets封装如下:
import axios, { AxiosError, AxiosResponse } from "@ohos/axios";
import {ResponseModel} from "../model/ResponseModel"
import { ConfigUtil as Config } from "./ConfigUtil";
// axios.defaults.baseURL = 'https://xiaomi.itying.com';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.timeout=5000; //超时间是5秒
export function HttpGet(apiUri:string):Promise<ResponseModel>{
let responseData: ResponseModel=new ResponseModel();
return axios.get(apiUri).then((response:AxiosResponse)=>{
responseData.success=true;
responseData.message=Config.HTTP_GET_SUCCESS;
responseData.result=response.data["result"];
return responseData;
}).catch((err:AxiosError)=>{
responseData.success=false;
responseData.message="Error:"+JSON.stringify(err);
responseData.result=[];
return responseData;
})
}
export function HttpPost<T>(apiUri:string,extraData:T):Promise<ResponseModel>{
let responseData: ResponseModel=new ResponseModel();
return axios.post<object,AxiosResponse,T>(apiUri,extraData).then((response:AxiosResponse)=>{
responseData.success=true;
responseData.message=Config.HTTP_POST_SUCCESS;
responseData.result=response.data["result"];
return responseData;
}).catch((err:AxiosError)=>{
responseData.success=false;
responseData.message="Error:"+JSON.stringify(err);
responseData.result=[];
return responseData;
})
}
export function HttpPut<T>(apiUri:string,extraData:T):Promise<ResponseModel>{
let responseData: ResponseModel=new ResponseModel();
return axios.put<object,AxiosResponse,T>(apiUri,extraData).then((response:AxiosResponse)=>{
responseData.success=true;
responseData.message=Config.HTTP_PUT_SUCCESS;
responseData.result=response.data["result"];
return responseData;
}).catch((err:AxiosError)=>{
responseData.success=false;
responseData.message="Error:"+JSON.stringify(err);
responseData.result=[];
return responseData;
})
}
export function HttpDelete(apiUri:string):Promise<ResponseModel>{
let responseData: ResponseModel=new ResponseModel();
return axios.delete(apiUri).then((response:AxiosResponse)=>{
responseData.success=true;
responseData.message=Config.HTTP_DELETE_SUCCESS;
responseData.result=response.data["result"];
return responseData;
}).catch((err:AxiosError)=>{
responseData.success=false;
responseData.message="Error:"+JSON.stringify(err);
responseData.result=[];
return responseData;
})
}
export function ReplaceUri(str: string) {
// public\upload\zon0TTXnXUs1z5meqZhP5aNF.png
//public/upload/zon0TTXnXUs1z5meqZhP5aNF.png
try {
return str.split("\\").join("/")
}catch{
return str
}
}
关于HarmonyOS 鸿蒙Next基于axios和Promise的网络框架封装的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。
案例怎么用的呀?
基于楼主HarmonyOS 鸿蒙Next封装的axios的用法
import { ConfigUtil as Config } from '../common/ConfigUtil'
import { HttpDelete, HttpGet, HttpPost, HttpPut } from '../common/HttpUtil'
import { ResponseModel } from '../model/ResponseModel'
import { UserInfoInterface, UserModel } from '../model/UserModel'
@Entry
@Component
export struct Index {
aboutToAppear() {
}
//Get 获取数据
getData() {
let apiUri:string=`${Config.SERVER}/httpGet?username=aaaa&age=20`
HttpGet(apiUri).then((response:ResponseModel)=>{
console.log("HttpGet...");
console.log(JSON.stringify(response));
})
}
//Post用于提交数据
postData() {
let apiUri:string= `${Config.SERVER}/api/httpPost`;
HttpPost<UserInfoInterface>(apiUri,{
username:"张三",
address:"北京市",
}).then((response:ResponseModel)=>{
console.log("HttpPost...");
console.log(JSON.stringify(response));
})
}
//Put用于修改数据
putData() {
let apiUri:string=`${Config.SERVER}/api/httpPut`;
HttpPut<UserModel>(apiUri,{
id:123,
username:"李四",
address:"哈哈哈"
}).then((response:ResponseModel)=>{
console.log("HttpPut...");
console.log(JSON.stringify(response));
})
}
//Delete用于删除数据
deleteData() {
let apiUri:string=`${Config.SERVER}/api/httpDelete`;
HttpDelete(apiUri).then((response:ResponseModel)=>{
console.log("HttpDelete...");
console.log(JSON.stringify(response));
})
}
build() {
Column() {
Button() {
Text("Get请求").fontSize(16).fontColor(Color.White)
}
.width('80%')
.height(50)
.margin({ top: 20 })
.onClick(() => {
this.getData()
})
Button() {
Text("Post请求").fontSize(16).fontColor(Color.White)
}
.width('80%')
.height(50)
.margin({ top: 20 })
.onClick(() => {
this.postData()
})
Button() {
Text("Put请求").fontSize(16).fontColor(Color.White)
}
.width('80%')
.height(50)
.margin({ top: 20 })
.onClick(() => {
this.putData()
})
Button() {
Text("Delete请求").fontSize(16).fontColor(Color.White)
}
.width('80%')
.height(50)
.margin({ top: 20 })
.onClick(() => {
this.deleteData()
})
}.height('100%')
.justifyContent(FlexAlign.Center)
.width("100%")
}
}
期待HarmonyOS能在未来推出更多针对特定场景的优化功能。
我也封装了一个,不过楼主的更好一些
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, Method } from '@ohos/axios';
import ResponseResult from './ResponseResult';
import logger from '../util/Logger';
import { systemDateTime } from '@kit.BasicServicesKit';
import { HashMap } from '@kit.ArkTS';
import Constant from '../common/Constant';
const TAG: string = "HttpUtil"
const timeout = 20000 // 20s超时
const baseUrl = 'https://xxx.xxx.com'
export function httpDefaultSetting() {
// default settings
axios.defaults.baseURL = baseUrl;
axios.defaults.timeout = timeout;
// default headers
axios.defaults.headers.common['Client-Type'] = 'xxx';
axios.defaults.headers.common['Client-Version'] = '1.0.4';
axios.defaults.headers.common['Os'] = 'hmos';
axios.defaults.headers.common['Token'] = 'xxx';
// for post
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
// 添加请求拦截器
axios.interceptors.request.use((config: InternalAxiosRequestConfig) => {
return transRequest(config);
}, (error: AxiosError) => {
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use((response: AxiosResponse) => {
return transResponse(response);
}, (error: AxiosError) => {
return Promise.reject(error);
});
}
/**
* 请在这里处理请求体的拦截器操作逻辑
*
*/
function transRequest(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig {
try {
let millis = systemDateTime.getTime();
config.headers['t'] = millis - Constant.offsetTime; // 同步时间
// 增加验签逻辑
// 验签可以仅在需要的请求中增加验签,通过增加特定的header属性来区分
} finally {
return config;
}
}
/**
* 请在这里处理请求结果的拦截器操作逻辑
*
*/
function transResponse(response: AxiosResponse): AxiosResponse {
try {
let millis = systemDateTime.getTime();
if (lt != 0 && millis - lt < 60000) return response; // 可选,性能优化 1分钟内避免重复处理
lt = millis
let headers: HashMap<string, ESObject> = JSON.parse(JSON.stringify(response.headers));
let t: number = headers['servertimestamp'];
Constant.offsetTime = millis - t;
return response;
} catch (e) {
console.error(e)
return response;
}
}
let lt = 0
/**
* Initiates an HTTP request to a given URL.
*
* @param url URL for initiating an HTTP request.
* @param params Params for initiating an HTTP request.
*/
export function httpGet<D>(url: string, params?: ESObject, headers?: ESObject): Promise<D> {
logger.debug(TAG, "httpGet: ");
return new Promise<D>((resolve: Function, reject: Function) => {
let startTime = systemDateTime.getTime()
axios.get<ResponseResult, AxiosResponse<ResponseResult>, null>(url, {
headers: headers,
// 指定请求超时的毫秒数(0 表示无超时时间)
timeout: timeout, // 超时
// `connectTimeout` 指定请求连接服务器超时的毫秒数(0 表示无超时时间)
// 如果请求连接服务器超过 `connectTimeout` 的时间,请求将被中断
// connectTimeout: 60000, // 文档和代码不一致,代码中无法设置连接超时时间
params: params,
})
.then((response: AxiosResponse<ResponseResult>) => {
let duration = (systemDateTime.getTime() - startTime).toString()
logger.debug(TAG, "httpGet: Success. duration=" + duration);
logger.debug(TAG, "--------------------------------------");
logger.debug(TAG, "config=" + JSON.stringify(response.config));
logger.debug(TAG, "status=" + response.status);
// logger.debug(TAG, "statusText=" + response.statusText); // always empty??
logger.debug(TAG, "headers=" + JSON.stringify(response.headers));
logger.debug(TAG, "data=" + JSON.stringify(response.data));
logger.debug(TAG, "--------------------------------------");
if (isSuccess(response)) {
if (isResultSuccess(response.data)) {
resolve(response.data.data);
} else {
const e: Error = { name: `${response.data.code}`, message: `${response.data.msg}` }
reject(e);
}
} else {
const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
reject(e);
}
})
.catch((reason: AxiosError) => {
logger.error(TAG, JSON.stringify(reason));
reject(reason)
})
});
}
function getRequestFormData(data?: ESObject): string | undefined {
if (data == undefined) return undefined;
let sb = new StringBuilder();
Object.keys(data).forEach((key: string) => {
sb.append(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
})
const formData = sb.build('&');
logger.debug(TAG, "getRequestFormData: formData=" + formData);
return formData;
}
function buildPostRequestHeader(isFormUrlencoded: boolean, headers?: Record<ESObject, ESObject>): Record<ESObject, ESObject> {
if (headers != null) {
headers['Content-Type'] = isFormUrlencoded ? 'application/x-www-form-urlencoded' : 'application/json'
return headers
}
return {
'Content-Type': isFormUrlencoded ? 'application/x-www-form-urlencoded' : 'application/json',
}
}
/**
* Initiates an HTTP request to a given URL.
*
* @param url URL for initiating an HTTP request.
* @param params Params for initiating an HTTP request.
*/
// o: { [s: string]: ESObject }
export function httpPost<D>(url: string, isFormUrlencoded: boolean = true, data?: ESObject, params?: ESObject, headers?: ESObject): Promise<D> {
// logger.debug(TAG, "httpPost: ");
return new Promise<D>((resolve: Function, reject: Function) => {
let startTime = systemDateTime.getTime()
axios.post(url, isFormUrlencoded ? getRequestFormData(data) : data, {
headers: buildPostRequestHeader(isFormUrlencoded, headers),
// 指定请求超时的毫秒数(0 表示无超时时间)
timeout: timeout, // 超时
// `connectTimeout` 指定请求连接服务器超时的毫秒数(0 表示无超时时间)
// 如果请求连接服务器超过 `connectTimeout` 的时间,请求将被中断
// connectTimeout: 60000, // 文档和代码不一致,代码中无法设置连接超时时间
params: params,
})
.then((response: AxiosResponse<ResponseResult>) => {
let duration = (systemDateTime.getTime() - startTime).toString()
logger.debug(TAG, "httpPost: Success. duration=" + duration);
logger.debug(TAG, "--------------------------------------");
logger.debug(TAG, "config=" + JSON.stringify(response.config));
logger.debug(TAG, "status=" + response.status);
// logger.debug(TAG, "statusText=" + response.statusText); // always empty??
logger.debug(TAG, "headers=" + JSON.stringify(response.headers));
logger.debug(TAG, "data=" + JSON.stringify(response.data));
logger.debug(TAG, "--------------------------------------");
if (isSuccess(response)) {
if (isResultSuccess(response.data)) {
resolve(response.data.data);
} else {
const e: Error = { name: `${response.data.code}`, message: `${response.data.msg}` }
reject(e);
}
} else {
const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
reject(e);
}
})
.catch((reason: AxiosError) => {
logger.error(TAG, JSON.stringify(reason));
reject(reason)
})
});
}
/**
* Initiates an HTTP request to a given URL.
*
* @param url URL for initiating an HTTP request.
* @param params Params for initiating an HTTP request.
*/
export function httpRequest<D>(url: string, method?: Method | string, data?: D, config?: AxiosRequestConfig<D>): Promise<ResponseResult> {
// logger.debug(TAG, "httpRequest: ");
return new Promise<ResponseResult>((resolve: Function, reject: Function) => {
let startTime = systemDateTime.getTime()
axios.request<ResponseResult, AxiosResponse<ResponseResult>, D>({
url: url,
method: method,
baseURL: baseUrl,
headers: config?.headers,
// 指定请求超时的毫秒数(0 表示无超时时间)
timeout: timeout, // 超时
// `connectTimeout` 指定请求连接服务器超时的毫秒数(0 表示无超时时间)
// 如果请求连接服务器超过 `connectTimeout` 的时间,请求将被中断
// connectTimeout: 60000, // 文档和代码不一致,代码中无法设置连接超时时间
params: config?.params,
data: data ?? config?.data
})
.then((response: AxiosResponse<ResponseResult>) => {
let duration = (systemDateTime.getTime() - startTime).toString()
logger.debug(TAG, "httpRequest: Success. duration=" + duration);
logger.debug(TAG, "--------------------------------------");
logger.debug(TAG, "config=" + JSON.stringify(response.config));
logger.debug(TAG, "status=" + response.status);
// logger.debug(TAG, "statusText=" + response.statusText); // always empty??
logger.debug(TAG, "headers=" + JSON.stringify(response.headers));
logger.debug(TAG, "data=" + JSON.stringify(response.data));
logger.debug(TAG, "--------------------------------------");
if (isSuccess(response)) {
if (isResultSuccess(response.data)) {
resolve(response.data.data);
} else {
const e: Error = { name: `${response.data.code}`, message: `${response.data.msg}` }
reject(e);
}
} else {
const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
reject(e);
}
})
.catch((reason: AxiosError) => {
logger.error(TAG, JSON.stringify(reason));
reject(reason)
})
});
}
function isSuccess(response: AxiosResponse): boolean {
return response.status >= 200 && response.status < 300
}
function isResultSuccess(result: ResponseResult): boolean {
return result.code == 0
}
StringBuilder是类似Java的字符串拼接类么?求共享,好像arkts没有啥好的拼接字符的工具类。
是的,自己封装的一个工具类,代码如下:
/**
- @Author wdq */ export class StringBuilder { private value: string[];
constructor() { this.value = []; }
append(str: string | number | undefined | null): StringBuilder { this.value.push(String(str)); return this; }
appendNotNull(str: string | number | undefined | null): StringBuilder { if (str != null) { this.value.push(String(str)); } return this; }
build(separator?: string): string { return this.value.join(separator); } }
暂时没遇到过,或者你代码发出来看看
主要的代码全部都有了,参考着写就行了
初始化设置一些默认值,一般在 EntryAbility 的 oncreate 调用即可
offsetTime 是什么?一般设置多少?
我这里的offsetTime指的是跟服务端的时间差,同步时间用的,逻辑是通过拿接口中服务端在header中的时间戳,跟本地时间戳的差值。具体参考上面的代码。