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 = [];