import { Http, Cryptogram, Kit } from '@easy-front-core-sdk/kits' import { ApiMethod } from './Enums' export interface IApiConfig { /** * appKey */ appKey: string /** * appSecret */ appSecret: string } export class RequestOptions { useLogBaseUrl?: boolean getSimpleResponse?: boolean = false } type authScopeType = 'snsapi_base' | 'snsapi_union_login' export class JosCoreFactory { private static CORE_MAP: Map = new Map() public static putCore(apiConfig: IApiConfig, enableLog = false): JosCore { let jdCore: JosCore = this.CORE_MAP.get(apiConfig.appKey) if (jdCore) return jdCore jdCore = new JosCore(apiConfig, enableLog) this.CORE_MAP.set(apiConfig.appKey, jdCore) return jdCore } public static getCore(appKey: string): JosCore { const jdCore: JosCore = this.CORE_MAP.get(appKey) if (!jdCore) { throw new Error(`需先调用 JosCoreFactory.putCore(apiConfig: IApiConfig),才能使用本方法`) } return jdCore } public static removeCore(appKey: string): boolean { return this.CORE_MAP.delete(appKey) } } export class JosCore { private _http = Http.getInstance() private _apiConfig: IApiConfig = null private authUrl = 'https://open-oauth.jd.com/oauth2' private baseUrl = 'https://api.jd.com/routerjson' private logBaseUrl = 'https://api-log.jd.com/routerjson' private apiVersion = '2.0' private enableLog: boolean constructor(apiConfig: IApiConfig, enableLog = false) { this.enableLog = enableLog if (apiConfig.appKey && apiConfig.appSecret) { this._apiConfig = apiConfig } else { throw new Error(`appKey or appSecret empty`) } } public generateOAuthUrl(redirect_uri: string, scope: authScopeType = 'snsapi_base', state?: string): string { return `${this.authUrl}/to_login?app_key=${this._apiConfig.appKey}&response_type=code&redirect_uri=${redirect_uri}&scope=${scope}&state=${state}` } public async getAccessToken(code: string) { const getAccessTokenUrl = `${this.authUrl}/access_token?app_key=${this._apiConfig.appKey}&app_secret=${this._apiConfig.appSecret}&grant_type=authorization_code&code=${code}` const response = await this._http.get(getAccessTokenUrl, { headers: { Accept: 'application/json', }, }) return response } public async refreshAccessToken(refresh_token: string) { const refreshAccessTokenUrl = `${this.authUrl}/refresh_token?app_key=${this._apiConfig.appKey}&app_secret=${this._apiConfig.appSecret}&grant_type=refresh_token&refresh_token=${refresh_token}` const response = await this._http.get(refreshAccessTokenUrl, { headers: { Accept: 'application/json', }, }) return response } private buildParams(apiMethod: ApiMethod, apiParams: any, timestamp: string, accessToken?: string) { let qStr = `360buy_param_json=${JSON.stringify(apiParams)}` if (accessToken) { qStr += `&access_token=${accessToken}` } const sign = this.makeSign(apiMethod, apiParams, timestamp, accessToken) qStr += `&app_key=${this._apiConfig.appKey}&method=${apiMethod}×tamp=${timestamp}&v=${this.apiVersion}&sign=${sign}` return qStr } private makeSign(apiMethod: ApiMethod, apiParams: any, timestamp: string, accessToken?: string) { let str = `${this._apiConfig.appSecret}360buy_param_json${JSON.stringify(apiParams)}` if (accessToken) { str += `access_token${accessToken}` } str += `app_key${this._apiConfig.appKey}method${apiMethod}timestamp${timestamp}v${this.apiVersion}${this._apiConfig.appSecret}` const sign = Cryptogram.md5(str).toUpperCase() return sign } public async request( apiMethod: ApiMethod, params: any, accessToken?: string, options: RequestOptions = { getSimpleResponse: true } ) { const now = new Date() const request_id = now.getTime() const logPrefix = `[jossdk requestid: ${request_id}]` const builtParams = this.buildParams(apiMethod, params, Kit.dateFormat(now), accessToken) const url = options?.useLogBaseUrl ? this.logBaseUrl : this.baseUrl if (this.enableLog) { console.log(`${logPrefix} url: ${url}`) console.log(`${logPrefix} request body: ${JSON.stringify(builtParams)}`) } const response = await this._http.post(url, builtParams, { headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8', Accept: 'application/json', }, timeout: 25000, }) if (this.enableLog) { console.log(`${logPrefix} response body: ${JSON.stringify(response)}`) } const { error_response } = response if (error_response) { throw new Error(`${apiMethod} error: ${error_response.code} ### ${error_response.zh_desc}`) } return options?.getSimpleResponse ? this.getSimpleResponse(apiMethod as string, response) : response } private getSimpleResponse(method: string, response: any) { const reg = /\./g const responce_name = `${method.replace(reg, '_')}_responce` const response_name = `${method.replace(reg, '_')}_response` return response[responce_name] ?? response[response_name] ?? response } }