鸿蒙ArkTs使用axios发起网络请求并对请求参数加密

下载安装axios

shell 复制代码
ohpm install @ohos/axios

需要权限

json5 复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:permission_internet",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          //inuse(使用时)、always(始终)。
          "when": "inuse"
        }
      }
    ]
  }
}

AES加密数据:

ts 复制代码
  //参数排序后序列化
  let jsonParams: string = JSON.stringify(obj)
  Logger.debug(TAG, jsonParams)

  //生成aes秘钥
  //创建秘钥生成器
  let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256')
  // 通过非对称密钥生成器,随机生成非对称密钥
  let promiseSymKey = symKeyGenerator.generateSymKeySync();
  //转换成可以读懂的字符串
  let key = buffer.from(promiseSymKey.getEncoded().data).toString('hex').substring(0, 32);

  //创建iv
  let iv = key.substring(0, 16);
  let ivParam: cryptoFramework.IvParamsSpec = {
    algName: 'IvParamsSpec',
    iv: {
      data: new Uint8Array(buffer.from(iv).buffer)
    }
  }

  //convertKey方法是通过秘钥生成symKey
  let symKey = symKeyGenerator.convertKeySync({ data: new Uint8Array(buffer.from(key).buffer) });

  //创建cipher
  let cipher = cryptoFramework.createCipher('AES256|CBC|PKCS7');

  //创建cipher之后才能初始化
  cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, ivParam);
  let output = cipher.doFinalSync({ data: new Uint8Array(buffer.from(jsonParams, 'utf-8').buffer) })
  let base64: util.Base64Helper = new util.Base64Helper();
  //加密后的数据
  let aesParams = base64.encodeToStringSync(output.data);

RSA加密数据:

extendtypescript 复制代码
  //RSA加密aes秘钥
  //将公钥转换
  let symKeyBlob: crypto.DataBlob = { data: base64.decodeSync(PUBLIC_KEY) };
  let aesGenerator = crypto.createAsyKeyGenerator('RSA1024');
  let pubPair = aesGenerator.convertKeySync(symKeyBlob, null);
  //生成加密器
  let encoder = crypto.createCipher('RSA1024|PKCS1');
  //初始化加密环境
  encoder.initSync(crypto.CryptoMode.ENCRYPT_MODE, pubPair.pubKey, null);
  //封装加密所需数据
  let encode = new util.TextEncoder();
  //开始加密
  let updateOutput = encoder.doFinalSync({ data: encode.encodeInto(key) });
  //转换字符串
  let rsaKay = buffer.from(updateOutput.data).toString("base64");
  //写入请求头
  config.headers[CryptoConstant.PRIVATE_KEY] = rsaKay;

加载中弹窗

ts 复制代码
import { ComponentContent, PromptAction } from '@kit.ArkUI';

class LoadingManager {
  contentNode: ComponentContent<Object> | undefined = undefined;
  promptAction: PromptAction | undefined = undefined;
  isShowing: number = 0

  show(uiContext: UIContext) {
    this.isShowing++;
    this.contentNode = new ComponentContent(uiContext, wrapBuilder(Loading));
    this.promptAction = uiContext.getPromptAction();
    this.promptAction.openCustomDialog(this.contentNode, {
      alignment: DialogAlignment.Center
    })
  }

  hide() {
    this.isShowing--;
    if (this.isShowing <= 0) {
      if (this.promptAction) {
        this.promptAction.closeCustomDialog(this.contentNode)
      }
    }
  }
}

let loadingManager = new LoadingManager()

export default loadingManager;


@Builder
function Loading() {
  Column() {
    LoadingProgress()
      .width($r('app.string.dimensions_50'))
      .height($r('app.string.dimensions_50'))
      .color(Color.White)
  }
  .width($r('app.string.dimensions_50'))
  .height($r('app.string.dimensions_50'))
  .backgroundColor($r('app.color.bg_00000000'))
  .justifyContent(FlexAlign.Center)
}

完整AxiosHttp.ets

ts 复制代码
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, Method } from '@ohos/axios';

import { GlobalThis, Logger, StringBuilder, StrUtil, ToastUtil } from '@yunkss/eftool';
import { ResponseBaseResult, ResponseResult } from '../model/ResponseResult';
import { deviceInfo, emitter, systemDateTime } from '@kit.BasicServicesKit';
import { ContentType } from '../constant/CommonConstant';
import { HttpConstant } from '../constant/HttpConstant';
import { HttpConfig } from '../utils/HttpConfig';
import { UserManager } from './UserManager';
import { buffer, TreeMap, util } from '@kit.ArkTS';
import { CryptoConstant } from '../constant/CryptoConstant';
import BuildProfile from '../../../../BuildProfile';
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { EmitterConstants } from '../constant/EmitterConstants';
import loadingManager from './LoadingManager';
import crypto from '@ohos.security.cryptoFramework';

const TAG: string = "HttpUtil:  "
const PUBLIC_KEY = "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGj8WNUSzCn0rHqfIXk9XPdJp60u\n" +
  "JnM+mVZVxY1lZmUCVA7t3eJZ0R0z1hUHkVb51eryDZcsz0QLSav3cmQv00ullK18\n" +
  "8aOs2SXZe6rcQf6XmOsVBqgADkrN+WePZJmb5Fr0NUkQ/sr7+R71cDZ87Y9QKm99\n" +
  "8BFOiWoEGxWWvDsTAgMBABF=";

export function httpDefaultSetting() {

  // default settings
  axios.defaults.baseURL = HttpConfig.BASE_URL;
  axios.defaults.timeout = HttpConstant.HTTP_TIMEOUT;

  // default headers
  //设备相关
  axios.defaults.headers.common['os'] = 'harmoney';
  axios.defaults.headers.common['device'] = deviceInfo.marketName;
  //用户相关
  axios.defaults.headers.common["token"] = UserManager.getToken();
  axios.defaults.headers.common["Authorization"] = UserManager.getToken();

  // for post
  axios.defaults.headers.post['Content-Type'] = ContentType.APPLICATION_JSON

  // 添加请求拦截器
  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);
  });
}

/**
 * 在这里处理请求体的拦截器操作逻辑
 */
async function transRequest(config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> {
  try {
    Logger.debug(TAG, "------------------Request------------------");
    Logger.debug(TAG, "httpUrl: " + config.baseURL + config.url);
    Logger.debug(TAG, "headers: " + JSON.stringify(config.headers));
    syncCryptoDataBySys(config)
  } catch (error) {
    let e: Error = error as Error
    Logger.error(TAG, e.message)
  } finally {
    return config;
  }
}

/**
 * 在这里处理请求结果的拦截器操作逻辑
 */
function transResponse(response: AxiosResponse): AxiosResponse {
  try {
    if (isSuccess(response)) {
      let data: ResponseBaseResult = response.data as ResponseBaseResult
      switch (data.code) {
        case HttpConstant.HTTP_OK:
        case HttpConstant.HTTP_OK_200:
          break
        case HttpConstant.HTTP_LOGOUT:
          // 退出登录
          emitter.emit({ eventId: EmitterConstants.LOGIN_OUT }, {
            data: {
              msg: data.msg,
            }
          });
          break
        default:
          if (data.msg != null && data.msg.length != 0) {
            ToastUtil.showToast(data.msg)
          }
          break
      }
    } else {
      ToastUtil.showToast(!StrUtil.isEmpty(response.statusText) ? response.statusText : $r('app.string.http_error_msg'))
    }
    return response;
  } catch (error) {
    let e: Error = error as Error
    ToastUtil.showToast(!StrUtil.isEmpty(e.message) ? e.message : $r('app.string.http_error_msg'))
    return response;
  }
}

export function httpGet<D>(url: string, config?: AxiosRequestConfig<D>,): Promise<D> {
  Logger.debug(TAG, "httpGet: ");

  let uiContext = GlobalThis.getInstance().getContext("EntryAbility")?.windowStage.getMainWindowSync().getUIContext()
  if (uiContext != undefined) {
    loadingManager.show(uiContext)
  }

  return new Promise<D>((resolve: Function, reject: Function) => {
    let startTime = systemDateTime.getTime()
    axios.get<ResponseResult<D>, AxiosResponse<ResponseResult<D>>, null>(url, {
      baseURL: config?.baseURL,
      headers: config?.headers,
      // 指定请求超时的毫秒数(0 表示无超时时间)
      timeout: HttpConstant.HTTP_TIMEOUT,
      params: config?.params,
    })
      .then((response: AxiosResponse<ResponseResult<D>>) => {
        let duration = (systemDateTime.getTime() - startTime).toString()
        Logger.debug(TAG, "------------------Response------------------");
        Logger.debug(TAG, "httpUrl" + config?.baseURL + config?.url);
        Logger.debug(TAG, "httpGet Success duration=" + duration);
        Logger.debug(TAG, "config=" + JSON.stringify(response.config));
        Logger.debug(TAG, "status=" + response.status);
        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);
        }
        loadingManager.hide()
      })
      .catch((reason: AxiosError) => {
        Logger.error(TAG, "httpUrl" + config?.baseURL + config?.url);
        Logger.error(TAG, JSON.stringify(reason));
        reject(reason)
        loadingManager.hide()
      })
  });
}

export function httpPost<D>(url: string, data?: ESObject, config?: AxiosRequestConfig<D>,
  isFormUrlencoded: boolean = true): Promise<D> {

  let uiContext = GlobalThis.getInstance().getContext("EntryAbility")?.windowStage.getMainWindowSync().getUIContext()
  if (uiContext != undefined) {
    loadingManager.show(uiContext)
  }

  return new Promise<D>((resolve: Function, reject: Function) => {

    let startTime = systemDateTime.getTime()
    let requestData: ESObject = isFormUrlencoded ? getRequestFormData(data ?? config?.data) : data ?? config?.data
    axios.post(
      url,
      requestData,
      {
        baseURL: config?.baseURL,
        headers: buildPostRequestHeader(isFormUrlencoded, config?.headers),
        // 指定请求超时的毫秒数(0 表示无超时时间)
        timeout: HttpConstant.HTTP_TIMEOUT,
        params: config?.params,
      }
    )
      .then((response: AxiosResponse<ResponseResult<D>>) => {
        let duration = (systemDateTime.getTime() - startTime).toString()
        Logger.debug(TAG, "------------------Response------------------");
        Logger.debug(TAG, "httpUrl" + config?.baseURL + config?.url);
        Logger.debug(TAG, "httpPost Success duration=" + duration);
        Logger.debug(TAG, "config=" + JSON.stringify(response.config));
        Logger.debug(TAG, "status=" + response.status);
        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);
        }
        loadingManager.hide()
      })
      .catch((reason: AxiosError) => {
        Logger.error(TAG, "httpUrl" + config?.baseURL + config?.url);
        Logger.error(TAG, JSON.stringify(reason));
        reject(reason)
        loadingManager.hide()
      })
  })
}

export function httpRequest<D>(url: string, method?: Method | string, data?: D,
  config?: AxiosRequestConfig<D>): Promise<ResponseResult<D>> {

  let uiContext = GlobalThis.getInstance().getContext("EntryAbility")?.windowStage.getMainWindowSync().getUIContext()
  if (uiContext != undefined) {
    loadingManager.show(uiContext)
  }

  return new Promise<ResponseResult<D>>((resolve: Function, reject: Function) => {
    let startTime = systemDateTime.getTime()
    axios.request<ResponseResult<D>, AxiosResponse<ResponseResult<D>>, D>({
      url: url,
      method: method,
      baseURL: config?.baseURL,
      headers: config?.headers,
      // 指定请求超时的毫秒数(0 表示无超时时间)
      timeout: HttpConstant.HTTP_TIMEOUT,
      params: config?.params,
      data: data ?? config?.data
    })
      .then((response: AxiosResponse<ResponseResult<D>>) => {
        let duration = (systemDateTime.getTime() - startTime).toString()
        Logger.debug(TAG, "------------------Response------------------");
        Logger.debug(TAG, "httpUrl" + config?.baseURL + config?.url);
        Logger.debug(TAG, "httpRequest Success duration=" + duration);
        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);
        }
        loadingManager.hide()
      })
      .catch((reason: AxiosError) => {
        Logger.error(TAG, "httpUrl" + config?.baseURL + config?.url);
        Logger.error(TAG, JSON.stringify(reason));
        reject(reason)
        loadingManager.hide()
      })
  });
}

function getRequestFormData(data?: ESObject): string | undefined {
  if (data == undefined) {
    return undefined;
  }
  let sb = new StringBuilder();
  let keys = Object.keys(data);
  keys.forEach((key: string) => {
    sb.append(`${key}=${data[key]}`)
    if (keys.indexOf(key) != keys.length - 1) {
      sb.append('&')
    }
  })
  let formData = sb.toString();
  return formData;
}

function buildPostRequestHeader(isFormUrlencoded: boolean,
  headers?: Record<ESObject, ESObject>): Record<ESObject, ESObject> {
  if (headers != null) {
    headers['Content-Type'] = isFormUrlencoded ? ContentType.APPLICATION_FORM : ContentType.APPLICATION_JSON
    return headers
  }
  return {
    'Content-Type': isFormUrlencoded ? ContentType.APPLICATION_FORM : ContentType.APPLICATION_JSON,
  }
}

function isSuccess(response: AxiosResponse): boolean {
  return response.status >= 200 && response.status < 300
}

function isResultSuccess(result: ResponseBaseResult): boolean {
  return result.code == HttpConstant.HTTP_OK
}

// 同步加密数据
export function syncCryptoDataBySys(config: InternalAxiosRequestConfig) {
  let treeMap: TreeMap<string, string> = new TreeMap()
  if (config.headers['Content-Type'] == ContentType.APPLICATION_FORM) {
    let data = StrUtil.asString(config.data);
    let params: string[] | undefined = data?.split("&");
    if (params != undefined) {
      params.forEach(param => {
        let paramKV: string[] = param.split("=");
        treeMap.set(paramKV[0], paramKV[1]);
      })
    }
  } else {
    let keys = Object.keys(config.data);
    keys.forEach((key: string) => {
      treeMap.set(key, config.data[key]);
    })
  }
  let obj: Record<string, string> = {};
  for (let entry of treeMap.entries()) {
    obj[Object(entry)[0]] = Object(entry)[1];
  }

  //参数排序后序列化
  let jsonParams: string = JSON.stringify(obj)
  Logger.debug(TAG, jsonParams)

  //AES加密
  //创建秘钥生成器
  let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256')
  // 通过非对称密钥生成器,随机生成非对称密钥
  let promiseSymKey = symKeyGenerator.generateSymKeySync();
  //转换成可以读懂的字符串
  let key = buffer.from(promiseSymKey.getEncoded().data).toString('hex').substring(0, 32);
  //创建iv
  let iv = key.substring(0, 16);
  let ivParam: cryptoFramework.IvParamsSpec = {
    algName: 'IvParamsSpec',
    iv: {
      data: new Uint8Array(buffer.from(iv).buffer)
    }
  }
  //convertKey方法是通过秘钥生成symKey
  let symKey = symKeyGenerator.convertKeySync({ data: new Uint8Array(buffer.from(key).buffer) });
  //创建cipher
  let cipher = cryptoFramework.createCipher('AES256|CBC|PKCS7');
  //创建cipher之后才能初始化
  cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, ivParam);
  let output = cipher.doFinalSync({ data: new Uint8Array(buffer.from(jsonParams, 'utf-8').buffer) })
  let base64: util.Base64Helper = new util.Base64Helper();
  //加密后的数据
  let aesParams = base64.encodeToStringSync(output.data);
  //写入请求体
  config.data = encodeURIComponent(CryptoConstant.SIGN) + "=" + encodeURIComponent(aesParams);

  //RSA加密aes秘钥
  //将公钥转换
  let symKeyBlob: crypto.DataBlob = { data: base64.decodeSync(PUBLIC_KEY) };
  let aesGenerator = crypto.createAsyKeyGenerator('RSA1024');
  let pubPair = aesGenerator.convertKeySync(symKeyBlob, null);
  //生成加密器
  let encoder = crypto.createCipher('RSA1024|PKCS1');
  //初始化加密环境
  encoder.initSync(crypto.CryptoMode.ENCRYPT_MODE, pubPair.pubKey, null);
  //封装加密所需数据
  let encode = new util.TextEncoder();
  //开始加密
  let updateOutput = encoder.doFinalSync({ data: encode.encodeInto(key) });
  //转换字符串
  let rsaKay = buffer.from(updateOutput.data).toString("base64");
  //写入请求头
  config.headers[CryptoConstant.PRIVATE_KEY] = rsaKay;

  Logger.debug(TAG, CryptoConstant.SIGN + ": " + aesParams)
  Logger.debug(TAG, CryptoConstant.PRIVATE_KEY + ": " + rsaKay)
}

// 同步加密数据
export function syncCryptoDataByRSA(data: string): string {
  //RSA加密aes秘钥
  //将公钥转换
  let base64: util.Base64Helper = new util.Base64Helper();
  let symKeyBlob: crypto.DataBlob = { data: base64.decodeSync(PUBLIC_KEY) };
  let aesGenerator = crypto.createAsyKeyGenerator('RSA1024');
  let pubPair = aesGenerator.convertKeySync(symKeyBlob, null);
  //生成加密器
  let encoder = crypto.createCipher('RSA1024|PKCS1');
  //初始化加密环境
  encoder.initSync(crypto.CryptoMode.ENCRYPT_MODE, pubPair.pubKey, null);
  //封装加密所需数据
  let encode = new util.TextEncoder();
  //开始加密
  let updateOutput = encoder.doFinalSync({ data: encode.encodeInto(data) });
  //转换字符串
  return buffer.from(updateOutput.data).toString("base64");
}

接口示例:

ts 复制代码
  // 登录
  login() {
    if (StrUtil.isEmpty(this.phone)) {
      ToastUtil.showToast($r('app.string.empty_phone_hint'))
      return
    }
    if (StrUtil.isEmpty(this.smsCode)) {
      ToastUtil.showToast($r('app.string.empty_sms_code_hint'))
      return
    }
    if (!this.isAgreeProtocol) {
      ToastUtil.showToast($r('app.string.agree_protocol_hint'))
      return
    }
    httpPost<LoginTokenModel>(HttpConfig.LLCB_LOGIN_TO_LOGIN, {
      phone: this.phone,
      smsCode: this.smsCode,
      client_id: LoginConstants.client_id,
      grant_type: LoginConstants.grant_type_sms,
      client_secret: LoginConstants.client_secret,
      userType: LoginConstants.userType,
      osType: LoginConstants.osType,
    }, {
      baseURL: HttpConfig.BASE_URL_THIRD_LOGIN_IP
    }).then((loginTokenModel) => {
      Logger.error("LoginPage ", JSONUtil.toJSONString(loginTokenModel))
    }).catch((e: Error) => {
      Logger.error("LoginPage ", e.message)
    })
  }
相关推荐
sone12138几秒前
计算机网络(第8版)第三章 数据链路层(3.4)
服务器·网络·计算机网络
Andy醒39 分钟前
HarmonyOS开发之使用Picker(从相册选择图片),并且通过Swiper组件实现图片预览
harmonyos·鸿蒙
问道飞鱼1 小时前
一文教你弄懂网络协议栈以及报文格式
网络·网络协议
张太行_1 小时前
ICMP协议用途
服务器·网络·智能路由器
Projectsauron1 小时前
MQTT 协议概述
网络·mqtt·通信协议
docuxu2 小时前
软考-信息安全-基础知识
网络·安全·web安全
Ja_小浩2 小时前
【计算机网络】socket编程 && 几个网络命令
服务器·网络·计算机网络
马丁的代码日记2 小时前
深入剖析 Netty 中 TCP 粘包和拆包问题的解决之道
服务器·网络·tcp/ip