mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-10-20 14:41:23 +08:00
611 lines
19 KiB
JavaScript
611 lines
19 KiB
JavaScript
// 预先导入和绑定常用模块及函数
|
|
const encrypt = require('./crypto')
|
|
const CryptoJS = require('crypto-js')
|
|
const { default: axios } = require('axios')
|
|
const logger = require('./logger')
|
|
const { PacProxyAgent } = require('pac-proxy-agent')
|
|
const http = require('http')
|
|
const https = require('https')
|
|
const tunnel = require('tunnel')
|
|
const fs = require('fs')
|
|
const path = require('path')
|
|
const tmpPath = require('os').tmpdir()
|
|
const {
|
|
cookieToJson,
|
|
cookieObjToString,
|
|
toBoolean,
|
|
generateRandomChineseIP,
|
|
} = require('./index')
|
|
const { URLSearchParams, URL } = require('url')
|
|
const { APP_CONF } = require('./config.json')
|
|
const { loadNeapiKey } = require('./neapiKey')
|
|
const {
|
|
getToken: antiCheatTokenV2,
|
|
} = require('../module/register_checktoken_v2')
|
|
const {
|
|
getToken: antiCheatTokenV3,
|
|
} = require('../module/register_checktoken_v3')
|
|
const registerNeapikey = require('../module/register_neapikey')
|
|
|
|
// 预先读取匿名token并缓存
|
|
const anonymous_token = fs.readFileSync(
|
|
path.resolve(tmpPath, './anonymous_token'),
|
|
'utf-8',
|
|
)
|
|
const xeapiPublicKeyPath = path.resolve(tmpPath, './xeapi_public_key')
|
|
let xeapi_public_key = null
|
|
const loadXeapiPublicKey = () => {
|
|
if (!xeapi_public_key && fs.existsSync(xeapiPublicKeyPath)) {
|
|
try {
|
|
xeapi_public_key = JSON.parse(
|
|
fs.readFileSync(xeapiPublicKeyPath, 'utf-8'),
|
|
)
|
|
} catch (error) {
|
|
console.log('[ERR]', error)
|
|
}
|
|
}
|
|
return xeapi_public_key
|
|
}
|
|
|
|
// 预先绑定常用函数和常量
|
|
const floor = Math.floor
|
|
const random = Math.random
|
|
const now = Date.now
|
|
const keys = Object.keys
|
|
const stringify = JSON.stringify
|
|
const parse = JSON.parse
|
|
const characters = 'abcdefghijklmnopqrstuvwxyz'
|
|
const charactersLength = characters.length
|
|
|
|
// 预先创建HTTP/HTTPS agents并重用
|
|
const createHttpAgent = () => new http.Agent({ keepAlive: true })
|
|
const createHttpsAgent = () => new https.Agent({ keepAlive: true })
|
|
|
|
// 预先计算WNMCID(只计算一次)
|
|
const WNMCID = (function () {
|
|
let randomString = ''
|
|
for (let i = 0; i < 6; i++) {
|
|
randomString += characters.charAt(floor(random() * charactersLength))
|
|
}
|
|
return `${randomString}.${now().toString()}.01.0`
|
|
})()
|
|
|
|
let NMTID = ''
|
|
let NMTID_RETRIES_LEFT = 3
|
|
|
|
// neapi 配置过期时只让一个请求去刷新,并发的其余请求共用同一次结果
|
|
let neapiUserStatus = ''
|
|
let neapiRefreshing = null
|
|
const refreshNeapiKey = (version) => {
|
|
if (!neapiRefreshing) {
|
|
neapiRefreshing = registerNeapikey({ version, behavior: 'update' }, null)
|
|
.catch((error) => console.log('[ERR]', error))
|
|
.finally(() => {
|
|
neapiRefreshing = null
|
|
})
|
|
}
|
|
return neapiRefreshing
|
|
}
|
|
|
|
// 预先定义osMap
|
|
const osMap = {
|
|
pc: {
|
|
os: 'pc',
|
|
appver: '3.1.17.204416',
|
|
osver: 'Microsoft-Windows-10-Professional-build-19045-64bit',
|
|
channel: 'netease',
|
|
},
|
|
linux: {
|
|
os: 'linux',
|
|
appver: '1.2.1.0428',
|
|
osver: 'Deepin 20.9',
|
|
channel: 'netease',
|
|
},
|
|
android: {
|
|
os: 'android',
|
|
appver: '8.20.20.231215173437',
|
|
osver: '14',
|
|
channel: 'xiaomi',
|
|
},
|
|
iphone: {
|
|
os: 'iPhone OS',
|
|
appver: '9.0.90',
|
|
osver: '16.2',
|
|
channel: 'distribution',
|
|
},
|
|
osx: {
|
|
os: 'osx',
|
|
appver: '3.1.10.5100',
|
|
osver: '15.5',
|
|
channel: 'netease',
|
|
},
|
|
}
|
|
|
|
// 预先定义userAgentMap
|
|
const userAgentMap = {
|
|
weapi: {
|
|
pc: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
|
|
},
|
|
linuxapi: {
|
|
linux:
|
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
|
},
|
|
api: {
|
|
pc: 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 Chrome/91.0.4472.164 NeteaseMusicDesktop/3.1.29.205117',
|
|
android:
|
|
'NeteaseMusic/9.5.61.260802021928(9005061);Dalvik/2.1.0 (Linux; U; Android 12; HBN-AL00 Build/cd737a2.0)',
|
|
iphone: 'NeteaseMusic 9.0.90/5038 (iPhone; iOS 16.2; zh_CN)',
|
|
},
|
|
}
|
|
|
|
// 预先定义常量
|
|
const DOMAIN = APP_CONF.domain
|
|
const API_DOMAIN = APP_CONF.apiDomain
|
|
const EAPI_DOMAIN = APP_CONF.eapiDomain
|
|
const XEAPI_DOMAIN = APP_CONF.xeapiDomain
|
|
const NEAPI_DOMAIN = APP_CONF.neapiDomain
|
|
const ENCRYPT_RESPONSE = APP_CONF.encryptResponse
|
|
const SPECIAL_STATUS_CODES = new Set([201, 302, 400, 502, 800, 801, 802, 803])
|
|
|
|
let xeapiSessionId = ''
|
|
let xeapiSessionKey = ''
|
|
|
|
// chooseUserAgent函数
|
|
const chooseUserAgent = (crypto, uaType = 'pc') => {
|
|
return (userAgentMap[crypto] && userAgentMap[crypto][uaType]) || ''
|
|
}
|
|
|
|
// cookie处理
|
|
const processCookieObject = (cookie, crypto) => {
|
|
const _ntes_nuid = CryptoJS.lib.WordArray.random(32).toString()
|
|
const os = osMap[cookie.os] || osMap['pc']
|
|
|
|
const processedCookie = {
|
|
...cookie,
|
|
__remember_me: 'true',
|
|
ntes_kaola_ad: '1',
|
|
_ntes_nuid: cookie._ntes_nuid || _ntes_nuid,
|
|
_ntes_nnid: cookie._ntes_nnid || `${_ntes_nuid},${now().toString()}`,
|
|
WNMCID: cookie.WNMCID || WNMCID,
|
|
WEVNSM: cookie.WEVNSM || '1.0.0',
|
|
osver: cookie.osver || os.osver,
|
|
deviceId: cookie.deviceId || global.deviceId,
|
|
os: cookie.os || os.os,
|
|
channel: cookie.channel || os.channel,
|
|
appver: cookie.appver || os.appver,
|
|
}
|
|
|
|
// 服务端下发条件为不带NMTID请求任意eapi加密方式接口
|
|
if (cookie.NMTID) {
|
|
processedCookie['NMTID'] = cookie.NMTID
|
|
} else if (NMTID) {
|
|
processedCookie['NMTID'] = NMTID
|
|
} else if (NMTID_RETRIES_LEFT <= 0 || crypto !== 'eapi') {
|
|
processedCookie['NMTID'] =
|
|
'00O' + CryptoJS.lib.WordArray.random(19).toString()
|
|
}
|
|
|
|
if (!processedCookie.MUSIC_U) {
|
|
processedCookie.MUSIC_A = processedCookie.MUSIC_A || anonymous_token
|
|
}
|
|
|
|
return processedCookie
|
|
}
|
|
|
|
// header cookie生成
|
|
const createHeaderCookie = (header) => {
|
|
const headerKeys = keys(header)
|
|
const cookieParts = new Array(headerKeys.length)
|
|
|
|
for (let i = 0, len = headerKeys.length; i < len; i++) {
|
|
const key = headerKeys[i]
|
|
cookieParts[i] =
|
|
encodeURIComponent(key) + '=' + encodeURIComponent(header[key])
|
|
}
|
|
|
|
return cookieParts.join('; ')
|
|
}
|
|
|
|
// requestId生成
|
|
const generateRequestId = () => {
|
|
return `${now()}_${floor(random() * 1000)
|
|
.toString()
|
|
.padStart(4, '0')}`
|
|
}
|
|
|
|
const createRequest = async (uri, data, options) => {
|
|
let token = ''
|
|
switch (options.checkToken) {
|
|
case 'v2':
|
|
// 每次实时获取反作弊 token,不缓存
|
|
token = await antiCheatTokenV2()
|
|
break
|
|
case 'v3':
|
|
// 每次实时获取反作弊 token,不缓存
|
|
token = await antiCheatTokenV3()
|
|
break
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
// 变量声明和初始化
|
|
const headers = options.headers ? { ...options.headers } : {}
|
|
const ip = options.realIP || options.ip || ''
|
|
|
|
// 加密方式选择
|
|
let crypto = options.crypto
|
|
if (crypto === '') {
|
|
crypto = APP_CONF.encrypt ? 'eapi' : 'api'
|
|
}
|
|
|
|
// IP头设置
|
|
if (ip) {
|
|
headers['X-Real-IP'] = ip
|
|
headers['X-Forwarded-For'] = ip
|
|
}
|
|
|
|
let cookie = options.cookie || {}
|
|
if (typeof cookie === 'string') {
|
|
cookie = cookieToJson(cookie)
|
|
}
|
|
|
|
if (typeof cookie === 'object') {
|
|
cookie = processCookieObject(cookie, crypto)
|
|
headers['Cookie'] = cookieObjToString(cookie)
|
|
}
|
|
let url = ''
|
|
let encryptData = ''
|
|
const csrfToken = cookie['__csrf'] || ''
|
|
|
|
const answer = { status: 500, body: {}, cookie: [] }
|
|
|
|
data.e_r = toBoolean(
|
|
options.e_r !== undefined
|
|
? options.e_r
|
|
: data.e_r !== undefined
|
|
? data.e_r
|
|
: ENCRYPT_RESPONSE,
|
|
)
|
|
// 根据加密方式处理
|
|
switch (crypto) {
|
|
case 'weapi':
|
|
headers['Referer'] = options.domain || DOMAIN
|
|
headers['User-Agent'] = options.ua || chooseUserAgent('weapi')
|
|
data.csrf_token = csrfToken
|
|
if (options.checkToken) {
|
|
headers['X-antiCheatToken'] = token
|
|
}
|
|
encryptData = encrypt.weapi(data)
|
|
url = (options.domain || DOMAIN) + '/weapi/' + uri.substr(5)
|
|
break
|
|
|
|
case 'linuxapi':
|
|
headers['User-Agent'] =
|
|
options.ua || chooseUserAgent('linuxapi', 'linux')
|
|
encryptData = encrypt.linuxapi({
|
|
method: 'POST',
|
|
url: (options.domain || DOMAIN) + uri,
|
|
params: data,
|
|
})
|
|
url = (options.domain || DOMAIN) + '/api/linux/forward'
|
|
break
|
|
|
|
case 'xeapi':
|
|
const xeapiPublicKey = loadXeapiPublicKey()
|
|
if (!xeapiPublicKey) {
|
|
throw new Error('xeapi public key is missing')
|
|
}
|
|
const xeapiOs = cookie.os === 'android' ? cookie.os : 'android'
|
|
const xeapiAppver =
|
|
cookie.os === 'android' && cookie.appver ? cookie.appver : '9.1.65'
|
|
const xeapiOsver =
|
|
cookie.os === 'android' && cookie.osver ? cookie.osver : '16'
|
|
const xeapiBuildver = cookie.buildver || now().toString().substr(0, 10)
|
|
headers['User-Agent'] = options.ua || chooseUserAgent('api', 'android')
|
|
headers['X-Client-Enc-State'] = 'ENCRYPTED'
|
|
headers['x-aeapi'] = true
|
|
headers['content-type'] =
|
|
'application/x-www-form-urlencoded;charset=utf-8'
|
|
headers['x-deviceid'] = cookie.deviceId
|
|
headers['x-os'] = xeapiOs
|
|
headers['x-osver'] = xeapiOsver
|
|
headers['x-appver'] = xeapiAppver
|
|
headers['x-sdeviceid'] = cookie.sDeviceId || cookie.deviceId
|
|
headers['x-buildver'] = xeapiBuildver
|
|
if (cookie.MUSIC_U) headers['x-music-u'] = cookie.MUSIC_U
|
|
if (options.checkToken) {
|
|
headers['X-antiCheatToken'] = token
|
|
}
|
|
const xeapiCookie = {
|
|
...cookie,
|
|
os: xeapiOs,
|
|
osver: xeapiOsver,
|
|
appver: xeapiAppver,
|
|
buildver: xeapiBuildver,
|
|
deviceId: cookie.deviceId,
|
|
sDeviceId: cookie.sDeviceId || cookie.deviceId,
|
|
}
|
|
headers['Cookie'] = cookieObjToString(xeapiCookie)
|
|
url = (options.domain || XEAPI_DOMAIN) + '/xeapi/' + uri.substr(5)
|
|
encryptData = encrypt.xeapi(uri, data, {
|
|
...options,
|
|
publicKeyState: xeapiPublicKey,
|
|
sessionId: xeapiSessionId,
|
|
sessionKey: xeapiSessionKey,
|
|
appver: xeapiAppver,
|
|
deviceId: cookie.deviceId,
|
|
os: xeapiOs,
|
|
uid: cookie.uid || cookie.userId || '',
|
|
})
|
|
break
|
|
|
|
case 'neapi':
|
|
const neapiKey = loadNeapiKey()
|
|
if (!neapiKey) {
|
|
throw new Error('neapi config is missing')
|
|
}
|
|
// 超过 circleTime 就后台刷新,本次仍用手上的配置
|
|
if (now() - neapiKey.fetchedAt >= neapiKey.circleTime) {
|
|
refreshNeapiKey(neapiKey.version)
|
|
}
|
|
const neapiCookie = {
|
|
osver: cookie.osver,
|
|
deviceId: cookie.deviceId,
|
|
os: cookie.os,
|
|
appver: cookie.appver,
|
|
versioncode: cookie.versioncode || '140',
|
|
mobilename: cookie.mobilename || '',
|
|
buildver: cookie.buildver || now().toString().substr(0, 10),
|
|
resolution: cookie.resolution || '1920x1080',
|
|
__csrf: csrfToken,
|
|
channel: cookie.channel,
|
|
requestId: generateRequestId(),
|
|
}
|
|
if (cookie.MUSIC_U) neapiCookie['MUSIC_U'] = cookie.MUSIC_U
|
|
if (cookie.MUSIC_A) neapiCookie['MUSIC_A'] = cookie.MUSIC_A
|
|
headers['Cookie'] = createHeaderCookie(neapiCookie)
|
|
headers['User-Agent'] = options.ua || chooseUserAgent('api', 'android')
|
|
headers['content-type'] =
|
|
'application/x-www-form-urlencoded;charset=utf-8'
|
|
// 服务端按 X-ER 选密钥,配置过期时由下面的 777/999 分支重拉并重试
|
|
headers['X-ER'] = String(neapiKey.version)
|
|
if (neapiUserStatus) headers['X-USER-STATUS'] = neapiUserStatus
|
|
|
|
const neapiBody = { ...data }
|
|
delete neapiBody.e_r
|
|
encryptData = encrypt.neapi(
|
|
new URLSearchParams(neapiBody).toString(),
|
|
neapiKey,
|
|
)
|
|
url = (options.domain || NEAPI_DOMAIN) + '/neapi/' + uri.substr(5)
|
|
break
|
|
|
|
case 'eapi':
|
|
case 'api':
|
|
// header创建
|
|
const header = {
|
|
osver: cookie.osver,
|
|
deviceId: cookie.deviceId,
|
|
os: cookie.os,
|
|
appver: cookie.appver,
|
|
versioncode: cookie.versioncode || '140',
|
|
mobilename: cookie.mobilename || '',
|
|
buildver: cookie.buildver || now().toString().substr(0, 10),
|
|
resolution: cookie.resolution || '1920x1080',
|
|
__csrf: csrfToken,
|
|
channel: cookie.channel,
|
|
requestId: generateRequestId(),
|
|
// clientSign: APP_CONF.clientSign,
|
|
}
|
|
|
|
if (cookie.MUSIC_U) header['MUSIC_U'] = cookie.MUSIC_U
|
|
if (cookie.MUSIC_A) header['MUSIC_A'] = cookie.MUSIC_A
|
|
if (options.checkToken) header['X-antiCheatToken'] = token
|
|
if (crypto === 'eapi' && cookie.NMTID) header['NMTID'] = cookie.NMTID
|
|
|
|
headers['Cookie'] = createHeaderCookie(header)
|
|
headers['User-Agent'] =
|
|
options.ua ||
|
|
(cookie.os === 'osx'
|
|
? 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
|
|
: chooseUserAgent('api', 'iphone'))
|
|
|
|
if (crypto === 'eapi') {
|
|
// headers['x-aeapi'] = true // 服务器会使用gzip压缩返回值
|
|
data.header = header
|
|
|
|
encryptData = encrypt.eapi(uri, data)
|
|
url = (options.domain || EAPI_DOMAIN) + '/eapi/' + uri.substr(5)
|
|
} else if (crypto === 'api') {
|
|
url = (options.domain || API_DOMAIN) + uri
|
|
encryptData = data
|
|
}
|
|
break
|
|
|
|
default:
|
|
console.log('[ERR]', 'Unknown Crypto:', crypto)
|
|
break
|
|
}
|
|
const use_e_r = (crypto === 'eapi' || crypto === 'weapi') && data.e_r
|
|
const use_xeapi = crypto === 'xeapi'
|
|
const use_neapi = crypto === 'neapi'
|
|
|
|
// settings创建
|
|
let settings = {
|
|
method: 'POST',
|
|
url: url,
|
|
headers: headers,
|
|
// neapi 的请求体就是容器本身,不是表单字段
|
|
data: use_neapi
|
|
? encryptData
|
|
: new URLSearchParams(encryptData).toString(),
|
|
httpAgent: createHttpAgent(),
|
|
httpsAgent: createHttpsAgent(),
|
|
}
|
|
|
|
// 自定义超时
|
|
if (options.timeout > 0) {
|
|
settings.timeout = options.timeout
|
|
}
|
|
|
|
// 使用返回值加密
|
|
if (use_e_r || use_xeapi || use_neapi) {
|
|
settings.encoding = null
|
|
settings.responseType = 'arraybuffer'
|
|
}
|
|
|
|
// 代理处理
|
|
if (options.proxy) {
|
|
if (options.proxy.indexOf('pac') > -1) {
|
|
const agent = new PacProxyAgent(options.proxy)
|
|
settings.httpAgent = agent
|
|
settings.httpsAgent = agent
|
|
} else {
|
|
try {
|
|
const purl = new URL(options.proxy)
|
|
if (purl.hostname) {
|
|
const isHttps = purl.protocol === 'https:'
|
|
const agent = tunnel[isHttps ? 'httpsOverHttp' : 'httpOverHttp']({
|
|
proxy: {
|
|
host: purl.hostname,
|
|
port: purl.port || 80,
|
|
proxyAuth:
|
|
purl.username && purl.password
|
|
? purl.username + ':' + purl.password
|
|
: '',
|
|
},
|
|
})
|
|
settings.httpsAgent = agent
|
|
settings.httpAgent = agent
|
|
settings.proxy = false
|
|
} else {
|
|
console.error('代理配置无效,不使用代理')
|
|
}
|
|
} catch (e) {
|
|
console.error('代理URL解析失败:', e.message)
|
|
}
|
|
}
|
|
} else {
|
|
settings.proxy = false
|
|
}
|
|
// console.log(settings.headers);
|
|
axios(settings)
|
|
.then(async (res) => {
|
|
const body = res.data
|
|
const setCookies = res.headers['set-cookie'] || []
|
|
|
|
const cleanCookie = (x) => x.replace(/\s*Domain=[^(;|$)]+;*/, '')
|
|
|
|
// 仅对真正未携带 NMTID 的探测请求采集并消耗重试次数
|
|
if (
|
|
crypto === 'eapi' &&
|
|
!NMTID &&
|
|
NMTID_RETRIES_LEFT > 0 &&
|
|
!cookie.NMTID
|
|
) {
|
|
NMTID_RETRIES_LEFT--
|
|
answer.cookie = setCookies.map((x) => {
|
|
const cleaned = cleanCookie(x)
|
|
const match = x.match(/(?:^|;\s*)NMTID=([^;]+)/)
|
|
if (match) {
|
|
//不需要处理竞争, 官方客户端真实操作
|
|
NMTID = match[1]
|
|
}
|
|
return cleaned
|
|
})
|
|
} else {
|
|
answer.cookie = setCookies.map(cleanCookie)
|
|
}
|
|
|
|
// 空值同样要记下来,否则状态恢复后会一直带着上一次的值
|
|
const userStatus = res.headers['x-user-status'] || ''
|
|
if (use_neapi) {
|
|
neapiUserStatus = userStatus
|
|
if (
|
|
(userStatus === '777' || userStatus === '999') &&
|
|
!options.neapiRetried
|
|
) {
|
|
// 配置已轮换:刷新后重试一次
|
|
await refreshNeapiKey(loadNeapiKey().version)
|
|
try {
|
|
resolve(
|
|
await createRequest(uri, data, {
|
|
...options,
|
|
neapiRetried: true,
|
|
}),
|
|
)
|
|
} catch (error) {
|
|
reject(error)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
// debug: 统一注释块,需要时取消注释查看请求/返回的原始密文
|
|
|
|
// logger.debug(`[${crypto}]`, uri)
|
|
// logger.debug(`[${crypto}] encrypted data:`, JSON.stringify(encryptData))
|
|
// logger.debug(
|
|
// `[RAW] [${crypto}]`,
|
|
// use_xeapi
|
|
// ? Buffer.from(body).toString('base64')
|
|
// : body.toString('hex').toUpperCase(),
|
|
// )
|
|
|
|
try {
|
|
if (use_xeapi) {
|
|
if (res.headers['x-encr-ssid'] && res.headers['x-encr-sskey']) {
|
|
xeapiSessionId = res.headers['x-encr-ssid']
|
|
xeapiSessionKey = res.headers['x-encr-sskey']
|
|
}
|
|
answer.body = encrypt.xeapiResDecrypt(Buffer.from(body))
|
|
} else if (use_neapi) {
|
|
answer.body = encrypt.neapiResDecrypt(
|
|
Buffer.from(body).toString(),
|
|
loadNeapiKey(),
|
|
)
|
|
} else if (use_e_r) {
|
|
answer.body = encrypt.eapiResDecrypt(
|
|
body.toString('hex').toUpperCase(),
|
|
headers['x-aeapi'],
|
|
)
|
|
} else {
|
|
answer.body =
|
|
typeof body === 'object' ? body : parse(body.toString())
|
|
}
|
|
|
|
if (answer.body.code) {
|
|
answer.body.code = Number(answer.body.code)
|
|
}
|
|
|
|
answer.status = Number(answer.body.code || res.status)
|
|
|
|
// 状态码检查(使用Set提升查找性能)
|
|
if (SPECIAL_STATUS_CODES.has(answer.body.code)) {
|
|
answer.status = 200
|
|
}
|
|
} catch (e) {
|
|
answer.body = body
|
|
answer.status = res.status
|
|
}
|
|
|
|
answer.status =
|
|
answer.status > 100 && answer.status < 600 ? answer.status : 400
|
|
|
|
if (answer.status === 200) {
|
|
resolve(answer)
|
|
} else {
|
|
console.log('[ERR]', answer)
|
|
reject(answer)
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
answer.status = 502
|
|
answer.body = { code: 502, msg: err.message || err }
|
|
console.log('[ERR]', answer)
|
|
reject(answer)
|
|
})
|
|
})
|
|
}
|
|
|
|
module.exports = createRequest
|