youzanyun-sdk-nodejs
Advanced tools
Comparing version 2.0.0-beta.9 to 2.0.0-beta.10
{ | ||
"name": "youzanyun-sdk-nodejs", | ||
"version": "2.0.0-beta.9", | ||
"version": "2.0.0-beta.10", | ||
"description": "有赞云 nodejs sdk", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -1,24 +0,1 @@ | ||
/** | ||
* ## 调用 | ||
* | ||
* 初次调用 | ||
* 1. 从环境变量中拿出 client-id, client-secret | ||
* 2. 然后通过 client-id, client-secret 去拿 token | ||
* 3. 缓存 token | ||
* 4. 用 token 去调用 api | ||
* | ||
* 再次调用 | ||
* 1. 判断是否有合法的 token | ||
* 2. 有合法的 token, 用合法的 token 去调用 api | ||
* 3. 没有合法的 token, 走初次调用流程 | ||
* | ||
* ## 防击穿 | ||
* | ||
* 如果获取获取 token 失败, 且原因在防击穿场景中(比如授权失败) 停止调用 5s | ||
* | ||
* ## token 缓存 | ||
* | ||
* token 缓存以 clientId+kdtId 为 key | ||
* | ||
*/ | ||
const TokenService = require('./token'); | ||
@@ -28,4 +5,7 @@ const FormData = require('form-data'); | ||
const Breakdown = require('./breakdown'); | ||
const { NEED_PREVENT_BREAKDOWN, OPEN_HOST } = require('./config'); | ||
const { OPEN_HOST } = require('./config'); | ||
const packageJson = require('../package.json'); | ||
const { TYPE } = require('./constants/type'); | ||
const { CODE_INVALID, CODE_SUCCESS } = require('./constants/code'); | ||
const { MAX_RETRIES } = require('./constants/other'); | ||
@@ -54,93 +34,130 @@ class ApiClient { | ||
async _getToken(kdtId, _axiosConfig) { | ||
async getToken(kdtId) { | ||
if (!kdtId) { | ||
throw 'kdtId必填'; | ||
} | ||
const { CLIENT_ID } = this._getCurrentSecret; | ||
// 是否处在防击穿的状态 | ||
const isInBreakdown = this._breakdown.isBreakdown(CLIENT_ID, kdtId); | ||
if (isInBreakdown) { | ||
throw new Error('处在防击穿状态'); | ||
} | ||
// 从缓存中获取token | ||
const tokenInfo = this._tokenCache.get(CLIENT_ID, kdtId, this.logger); | ||
this.logger.info('dktest-缓存中tokenInfo', tokenInfo); | ||
// 获取 token | ||
// 1. 首先从缓存里面获取 | ||
// 2. 如果缓存里面没有, 调接口获取 | ||
const tokenFromCache = this._tokenCache.get(CLIENT_ID, kdtId); | ||
const { expires, token } = tokenInfo || {}; | ||
if (token && +new Date() < expires) { | ||
this.logger.info('dktest-取用缓存token', token); | ||
if (tokenFromCache) { | ||
return tokenFromCache; | ||
return token; | ||
} | ||
// 去远程获取 | ||
const token = await this._tokenService.getToken( | ||
{ kdtId, type: 'cloud_function' }, | ||
_axiosConfig, | ||
// 重新获取token | ||
const data = await this._tokenService.getToken( | ||
{ kdtId, type: TYPE.CLOUD_FUNCTION }, | ||
this.logger, | ||
); | ||
// 缓存token | ||
this._tokenCache.set({ CLIENT_ID, kdtId, data }); | ||
return data && data.access_token; | ||
} | ||
if (token) { | ||
// token 有效, 缓存 | ||
this._tokenCache.set({ CLIENT_ID, kdtId, token }); | ||
return token; | ||
} | ||
// token 无效, 判断是否需要防击穿 | ||
if (NEED_PREVENT_BREAKDOWN.includes(token)) { | ||
// 是否处在防击穿的状态 | ||
} | ||
/** | ||
* 免鉴权 | ||
* @param {object} apiParams | ||
* @param {string} apiParams.api | ||
* @param {string} apiParams.version | ||
* @param {object} apiParams.params | ||
* @param {object} apiParams.files | ||
* @param {number} apiParams.kdtId | ||
* @param {object} axiosConfig | ||
* @returns {Promise<object>} | ||
*/ | ||
callApi(apiParams, axiosConfig, logger) { | ||
this.logger = logger; | ||
return new Promise((resolve, reject) => { | ||
const config = { apiParams, axiosConfig }; | ||
// 缓存请求 | ||
const request = () => this.invoke(config); | ||
// 添加配置 | ||
config.retryCount = 0; | ||
config.success = response => { | ||
this.logger.info('dktest-success', response); | ||
const { code, data } = response.data || {}; | ||
if (CODE_SUCCESS.includes(+code)) { | ||
resolve(data); | ||
} else if (CODE_INVALID.includes(+code) && config.retryCount <= MAX_RETRIES.TOKEN_INVALID) { | ||
// 重试请求 | ||
request(); | ||
} else { | ||
reject(JSON.stringify(response.data)); | ||
} | ||
}; | ||
config.fail = error => { | ||
this.logger.info('dktest-fail', error.response); | ||
reject(error); | ||
}; | ||
// 初次发送请求 | ||
request(); | ||
}); | ||
} | ||
// 网关Api调用 | ||
async callApi({ api, version, params, files, kdtId }, _axiosConfig) { | ||
let token; | ||
// 请求 | ||
async invoke(config = {}) { | ||
this.logger.info('dktest-invoke-请求进来了', config.retryCount); | ||
const { apiParams = {}, axiosConfig = {}, success, fail } = config; | ||
const { api, version, params, files, kdtId } = apiParams; | ||
config.retryCount++; | ||
try { | ||
const tokenResult = await this._getToken(kdtId, _axiosConfig); | ||
token = tokenResult.access_token; | ||
} catch (e) { | ||
throw e; | ||
// 获取token | ||
const token = await this.getToken(kdtId); | ||
// 发送请求 | ||
const response = await this._call( | ||
{ | ||
api, | ||
version, | ||
params, | ||
files, | ||
token, | ||
}, | ||
axiosConfig, | ||
); | ||
return success(response); | ||
} catch (error) { | ||
// 结束请求 | ||
return fail(error); | ||
} | ||
const result = this._call( | ||
{ | ||
api, | ||
version, | ||
params, | ||
token, | ||
files, | ||
}, | ||
_axiosConfig, | ||
); | ||
return result; | ||
} | ||
async _call({ api, version, token, params, files }, _axiosConfig) { | ||
let url = ''; | ||
if (token) { | ||
url = `https://${this._openHost}/api/${api}/${version}?access_token=${token}`; | ||
} else { | ||
url = `https://${this._openHost}/api/auth_exempt/${api}/${version}`; | ||
} | ||
async _call({ api, version, params, files, token }, axiosConfig) { | ||
const url = `https://${this._openHost}/api/${api}/${version}?access_token=${token}`; | ||
let response; | ||
if (files && Object.keys(files).length > 0) { | ||
response = await this._requestMultipart(url, params, files, _axiosConfig); | ||
return this._requestMultipart(url, params, files, axiosConfig); | ||
} else { | ||
response = await this._requestJson(url, params, _axiosConfig); | ||
return this._requestJson(url, params, axiosConfig); | ||
} | ||
if (response.data.success) { | ||
return response.data.data; | ||
} else { | ||
throw new Error(`请求${url}出错: ${JSON.stringify(response.data)}`); | ||
} | ||
} | ||
async _requestJson(url, data, _axiosConfig = {}) { | ||
let response = await this._httpClient.request({ | ||
..._axiosConfig, | ||
url, | ||
method: 'post', | ||
data, | ||
headers: { | ||
'User-Agent': `youzanyun-sdk-nodejs ${packageJson.version}-Node`, | ||
async _requestJson(url, data, axiosConfig = {}) { | ||
let response = await this._httpClient.request( | ||
{ | ||
...axiosConfig, | ||
url, | ||
method: 'post', | ||
data, | ||
headers: { | ||
'User-Agent': `youzanyun-sdk-nodejs ${packageJson.version}-Node`, | ||
}, | ||
}, | ||
}); | ||
this.logger, | ||
); | ||
return response; | ||
} | ||
async _requestMultipart(url, data, files, _axiosConfig = {}) { | ||
async _requestMultipart(url, data, files, axiosConfig = {}) { | ||
let form = new FormData(); | ||
@@ -156,15 +173,18 @@ data = data || {}; | ||
let response = await this._httpClient.request({ | ||
..._axiosConfig, | ||
url, | ||
method: 'post', | ||
data: form, | ||
headers: Object.assign( | ||
{}, | ||
{ | ||
'User-Agent': `youzanyun-sdk-nodejs ${packageJson.version}-NodeJs`, | ||
}, | ||
form.getHeaders(), | ||
), | ||
}); | ||
let response = await this._httpClient.request( | ||
{ | ||
...axiosConfig, | ||
url, | ||
method: 'post', | ||
data: form, | ||
headers: Object.assign( | ||
{}, | ||
{ | ||
'User-Agent': `youzanyun-sdk-nodejs ${packageJson.version}-NodeJs`, | ||
}, | ||
form.getHeaders(), | ||
), | ||
}, | ||
this.logger, | ||
); | ||
return response; | ||
@@ -171,0 +191,0 @@ } |
@@ -50,3 +50,4 @@ const https = require('https'); | ||
*/ | ||
request(options) { | ||
request(options, logger) { | ||
this.logger = logger; | ||
let { url, baseURL } = options; | ||
@@ -58,4 +59,8 @@ | ||
if (!this.enableProxy || this.ignoreHostSet.has(requestUrl.hostname)) { | ||
this.logger.info('dktest-不代理'); | ||
res = this._doRequest(options); | ||
} else { | ||
this.logger.info('dktest-代理'); | ||
let scheme = requestUrl.protocol.substr(0, requestUrl.protocol.length - 1); | ||
@@ -84,2 +89,4 @@ let headers = Object.assign(options.headers || {}, { | ||
console.log('config', config); | ||
this.logger.info('dktest-request请求配置', config); | ||
let res = axios.request(config); | ||
@@ -86,0 +93,0 @@ return res; |
@@ -0,1 +1,6 @@ | ||
function getTokenCacheName(clientId, kdtId) { | ||
if (!(clientId && kdtId)) return ''; | ||
return `${clientId}-${kdtId}`; | ||
} | ||
/** | ||
@@ -10,13 +15,25 @@ * 缓存 access_token, 以 `CLIENT_ID-${kdtId}` 为 key | ||
class TokenCache { | ||
_store = {}; | ||
store = {}; | ||
get(clientId, kdtId) { | ||
if (this._store[`${clientId}-${kdtId}`]) { | ||
return this._store[`${clientId}-${kdtId}`]; | ||
get(clientId, kdtId, logger) { | ||
const currentTokenInfoName = getTokenCacheName(clientId, kdtId); | ||
if (!currentTokenInfoName) return false; | ||
logger.info('dktest-缓存中所有token信息', this.store); | ||
if (this.store[currentTokenInfoName]) { | ||
return this.store[currentTokenInfoName]; | ||
} | ||
return false; | ||
} | ||
set(clientId, kdtId, tokenData) { | ||
this._store[`${clientId}-${kdtId}`] = tokenData; | ||
set(clientId, kdtId, tokenInfo) { | ||
const currentTokenInfoName = getTokenCacheName(clientId, kdtId); | ||
if (!(currentTokenInfoName && tokenInfo)) return false; | ||
this.store[currentTokenInfoName] = { | ||
token: tokenInfo.access_token, | ||
expires: tokenInfo.expires, | ||
}; | ||
return true; | ||
@@ -23,0 +40,0 @@ } |
@@ -72,2 +72,3 @@ const config = require('./config'); | ||
}, | ||
logger, | ||
_axiosConfig = {}, | ||
@@ -108,4 +109,8 @@ ) { | ||
console.log('getToken requestParams', requestParams, _axiosConfig); | ||
logger.info('dktest-getToken请求参数', requestParams); | ||
let response = await this.httpClient.request(requestParams); | ||
if (response.data.success) { | ||
logger.info('dktest-getToken请求响应', response.data.data); | ||
return response.data.data; | ||
@@ -112,0 +117,0 @@ } else { |
@@ -8,3 +8,3 @@ process.env.OPENSDK_CLIENTID = 'a4a06f27443a541400'; | ||
const sdk = require('./lib'); | ||
const sdk = require('./src/index'); | ||
@@ -11,0 +11,0 @@ const http_main_handler = async () => { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
34770
27
1081
13
2