王学岗Axios的data加密报错的问题

发布于:2025-08-03 ⋅ 阅读:(11) ⋅ 点赞:(0)
import axios, {AxiosHeaders, AxiosRequestConfig, AxiosResponse} from 'axios';
import {BASEURL1} from '@/src/utils/constant_utils';
import {Platform} from 'react-native';
import {ApiResponse} from '@/src/beans/api_response';
import {getLoginModel} from '@/src/utils/keychain_util';
import CryptoUtils from '@/src/utils/crypto_utils';
import {cryptoObjAES, cryptoObjRSA, CryTokenDataManager} from '@/src/model/cry_token_data_util';

export interface GlobalConfig {
  baseurl: string;
  headers: Record<string, string>;
  commonParams?: Record<string, unknown>;
  commonData?: Record<string, unknown>;
  encrypt: boolean;
  timeout: number;
}

export interface RequestOptions<R, D = any> extends Partial<GlobalConfig> {
  url: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  params?: Record<string, any>;
  data?: D;
}

let platformAuthorization = '';
if (Platform.OS === 'android') {
  platformAuthorization = 'Basic YW5kcm9pZDphbmRyb2lkX3NlY3JldA==';
} else if (Platform.OS === 'ios') {
  platformAuthorization = 'Basic aW9zOmlvc19zZWNyZXQ=';
} else {
  platformAuthorization = 'Basic YW5kcm9pZDphbmRyb2lkX3NlY3JldA==';
}

export const defaultConfig: GlobalConfig = {
  baseurl: BASEURL1,
  headers: {
    'Content-Type': 'application/json',
    'origin-domain': 'saas.test1.h5e.adre45.com',
    'saas-version': '5.8.6',
    Authorization: platformAuthorization,
    'Identity-Type': 'player',
  },
  commonParams: {},
  commonData: {device: '3'},
  encrypt: true,
  timeout: 20_000,
};

// 扩展 AxiosRequestConfig,支持存放每次请求的 IV 和随机串
declare module 'axios' {
  export interface AxiosRequestConfig {
    __mergedConfig?: GlobalConfig;
    metadata?: {
      startTime: number;
      hashStr: string;
    };
  }
}

export const axiosInstance = axios.create();

// 请求拦截器
axiosInstance.interceptors.request.use(async config => {
  const hashStr = CryTokenDataManager.generateRandomString();
  config.metadata = {startTime: Date.now(), hashStr};
  // 3. 合并配置
  const opt = ((config as any).__mergedConfig as GlobalConfig) || defaultConfig;
  config.baseURL = opt.baseurl;
  config.timeout = opt.timeout;
  // 4. 处理 headers
  const headers = new AxiosHeaders(config.headers);
  Object.entries(opt.headers).forEach(([k, v]) => headers.set(k, v));
  if (opt.encrypt) {
    const globalSecret = cryptoObjRSA(hashStr);
    headers.set('GlobalSecretKey', globalSecret);
  }
  const loginModel = await getLoginModel();
  const access_token = loginModel?.access_token;
  if (access_token) {
    headers.set('saas-auth', `bearer ${loginModel.access_token}`);
  } else {
    console.log(`[Request===>loginMod]  ${loginModel}`);
  }
  config.headers = headers;

  // 5. 合并 params / body
  config.params = {...config.params, ...opt.commonParams};
  if (config.data !== undefined) {
    const mergedBody = {...opt.commonData, ...config.data};
    if (opt.encrypt) {
      // config.data 已经是加密后的字符串,不希望 Axios 再自动对它做 JSON.stringify 或其它处理,否则会出错(变成二次序列化、内容被破坏)。
      config.transformRequest = [];
      const raw = JSON.stringify({...opt.commonData, ...(config.data as object)});
      config.data = cryptoObjAES.encrypt(raw, hashStr);
    } else {
      config.data = mergedBody;
    }
  }

  console.log(`[Request未加密] ${config.method?.toUpperCase()} ${config.baseURL}${config.url}`, {
    params: config.params,
    headers: config.headers,
    data: config.data,
    timeout: config.timeout + 'ms',
  });
  console.log(`[Request加密] ${config.data}`);
  return config;
});

// 响应拦截器
axiosInstance.interceptors.response.use(
  async (response: AxiosResponse<ApiResponse<any>>) => {
    const {config, status, data} = response;
    //获取到解密用的密钥
    const meta = config.metadata;
    const duration = meta ? Date.now() - meta.startTime : undefined;
    //打印返回的Response
    console.log(`[Response] ${config.method?.toUpperCase()} ${config.baseURL}${config.url} → ${status}` + (duration != null ? ` (${duration}ms)` : ''), {data});
    //如果解密的密钥不为空,并且需要解密
    if (meta && config.__mergedConfig?.encrypt) {
      //获取解密的字符串
      const decryptedStr = cryptoObjAES.decrypt(data.toString(), meta.hashStr);
      //打印解密后的数据
      console.log(`[Response(解密)] ${config.method?.toUpperCase()} ${config.baseURL}${config.url} → ${status}` + (duration != null ? ` (${duration}ms)` : ''), {decryptedStr});
      const decrypted = JSON.parse(decryptedStr);
      if (decrypted != null && typeof decrypted === 'object' && typeof decrypted.code === 'number' && Object.prototype.hasOwnProperty.call(decrypted, 'data')) {
        if (decrypted.code !== 200) {
          console.error('[API Error]', config.url, decrypted.msg);
          return Promise.reject(new Error(decrypted.msg));
        }
        return decrypted.data;
      } else {
        return decrypted;
      }
    } else {
      //不需要解密
      if (data != null && typeof data === 'object' && typeof data.code === 'number' && Object.prototype.hasOwnProperty.call(data, 'data')) {
        if (data.code !== 200) {
          console.error('[API Error]', config.url, data.msg);
          return Promise.reject(new Error(data.msg));
        }
        //返回标准的数据
        return data.data;
      } else {
        //返回非标准的数据
        return data;
      }
    }
  },
  error => {
    console.error(`[Response 直接崩溃的Error]===>${error}`);
    const cfg = error.config as AxiosRequestConfig;
    const start = cfg.metadata?.startTime;
    const elapsed = start ? Date.now() - start : null;
    console.error(`[Response Error] ${cfg.method?.toUpperCase()} ${cfg.baseURL}${cfg.url}` + (elapsed != null ? ` (${elapsed}ms)` : ''), {
      message: error.message,
      ...(error.response && {status: error.response.status, data: error.response.data}),
    });
    return Promise.reject(error);
  },
);

/**
 * 通用请求函数
 */
export async function aaasRequest<R, D = any>(options: RequestOptions<R, D>): Promise<R> {
  const merged: GlobalConfig = {
    ...defaultConfig,
    ...options,
    headers: {...defaultConfig.headers, ...(options.headers ?? {})},
    commonParams: {...defaultConfig.commonParams, ...(options.commonParams ?? {})},
    commonData: {...defaultConfig.commonData, ...(options.commonData ?? {})},
  };

  const axiosConfig: AxiosRequestConfig = {
    url: options.url,
    method: options.method,
    params: options.params,
    data: options.data,
    __mergedConfig: merged,
  };

  return axiosInstance.request<R, R>(axiosConfig);
}

Axios,data加密各种报错,加下面这句代码就好了
// config.data 已经是加密后的字符串,不希望 Axios 再自动对它做 JSON.stringify 或其它处理,否则会出错(变成二次序列化、内容被破坏)。
config.transformRequest = [];


网站公告

今日签到

点亮在社区的每一天
去签到