From f7132eba6343a4ec1e1e70df213bf2530445db26 Mon Sep 17 00:00:00 2001 From: overwriter <9856mmm@gmail.com> Date: Fri, 12 Jul 2024 23:18:37 +0800 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20=E8=AF=B7=E6=B1=82=E7=9A=84data?= =?UTF-8?q?=E4=B8=8D=E8=A6=86=E7=9B=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/aidj_content_rcmd.js | 2 +- module/api.js | 10 ++++++++-- util/request.js | 15 ++++++++++----- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/module/aidj_content_rcmd.js b/module/aidj_content_rcmd.js index e580b1d..f8e118c 100644 --- a/module/aidj_content_rcmd.js +++ b/module/aidj_content_rcmd.js @@ -2,7 +2,7 @@ // 实际请求参数如下, 部分内容省略, 敏感信息已进行混淆 // 可按需修改此 API 的代码 -/* {"extInfo":"{\"lastRequestTimestamp\":1692358373509,\"lbsInfoList\":[{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692358543},{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692055283}],\"listenedTs\":false,\"noAidjToAidj\":true}","header":"{}","e_r":true} */ +/* {"extInfo":"{\"lastRequestTimestamp\":1692358373509,\"lbsInfoList\":[{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692358543},{\"lat\":40.23076381,\"lon\":129.07545186,\"time\":1692055283}],\"listenedTs\":false,\"noAidjToAidj\":true}","header":"{}"} */ const createOption = require('../util/option.js') module.exports = (query, request) => { diff --git a/module/api.js b/module/api.js index f4d5eac..6de8689 100644 --- a/module/api.js +++ b/module/api.js @@ -2,8 +2,14 @@ const createOption = require('../util/option.js') module.exports = (query, request) => { const method = query.method || 'POST' const uri = query.uri - const data = - typeof query.data === 'string' ? JSON.parse(query.data) : query.data || {} + let data = {} + try { + data = + typeof query.data === 'string' ? JSON.parse(query.data) : query.data || {} + } catch (e) { + data = {} + } + const crypto = query.crypto || '' const res = request(method, uri, data, createOption(query, crypto)) diff --git a/util/request.js b/util/request.js index 9f51510..15f2491 100644 --- a/util/request.js +++ b/util/request.js @@ -86,18 +86,19 @@ const createRequest = (method, uri, data = {}, options) => { // console.log(options.cookie, headers['Cookie']) let url = '' + let encryptData = '' // 目前任意uri都支持三种加密方式 if (options.crypto === 'weapi') { headers['Referer'] = 'https://music.163.com' headers['User-Agent'] = options.ua || chooseUserAgent('pc') let csrfToken = (headers['Cookie'] || '').match(/_csrf=([^(;|$)]+)/) data.csrf_token = csrfToken ? csrfToken[1] : '' - data = encrypt.weapi(data) + encryptData = encrypt.weapi(data) url = APP_CONF.domain + '/weapi/' + uri.substr(5) } else if (options.crypto === 'linuxapi') { headers['User-Agent'] = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36' - data = encrypt.linuxapi({ + encryptData = encrypt.linuxapi({ method: method, url: APP_CONF.apiDomain + uri, params: data, @@ -137,18 +138,22 @@ const createRequest = (method, uri, data = {}, options) => { let eapiEncrypt = () => { data.header = header - data = encrypt.eapi(uri, data) + encryptData = encrypt.eapi(uri, data) url = APP_CONF.apiDomain + '/eapi/' + uri.substr(5) } if (options.crypto === 'eapi') { eapiEncrypt() } else if (options.crypto === 'api') { url = APP_CONF.apiDomain + uri + encryptData = data } else if (options.crypto === '') { // 加密方式为空,以配置文件的加密方式为准 if (APP_CONF.encrypt) { eapiEncrypt() - } else url = APP_CONF.apiDomain + uri + } else { + url = APP_CONF.apiDomain + uri + encryptData = data + } } } else { // 未知的加密方式 @@ -160,7 +165,7 @@ const createRequest = (method, uri, data = {}, options) => { method: method, url: url, headers: headers, - data: new URLSearchParams(data).toString(), + data: new URLSearchParams(encryptData).toString(), httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }), } From 656a69e07e3c853056c3ef186a3e58ec01dc2d02 Mon Sep 17 00:00:00 2001 From: overwriter <9856mmm@gmail.com> Date: Fri, 12 Jul 2024 23:24:40 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20eapi=E8=BF=94=E5=9B=9E=E5=80=BC?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E5=8F=AF=E8=A2=AB=E6=8E=A7=E5=88=B6=EF=BC=9B?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=B8=8D=E5=8A=A0=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/config.json | 2 +- util/request.js | 28 ++++++++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/util/config.json b/util/config.json index 33de888..3dbfad1 100644 --- a/util/config.json +++ b/util/config.json @@ -13,6 +13,6 @@ "apiDomain": "https://interface.music.163.com", "domain": "https://music.163.com", "encrypt": true, - "encryptResponse": true + "encryptResponse": false } } \ No newline at end of file diff --git a/util/request.js b/util/request.js index 15f2491..10b5997 100644 --- a/util/request.js +++ b/util/request.js @@ -140,6 +140,7 @@ const createRequest = (method, uri, data = {}, options) => { data.header = header encryptData = encrypt.eapi(uri, data) url = APP_CONF.apiDomain + '/eapi/' + uri.substr(5) + data.e_r = data.e_r != undefined ? data.e_r : APP_CONF.encryptResponse // 用于加密eapi接口的返回值 } if (options.crypto === 'eapi') { eapiEncrypt() @@ -170,6 +171,14 @@ const createRequest = (method, uri, data = {}, options) => { httpsAgent: new https.Agent({ keepAlive: true }), } + if (data.e_r) { + settings = { + ...settings, + encoding: null, + responseType: 'arraybuffer', + } + } + if (options.proxy) { if (options.proxy.indexOf('pac') > -1) { settings.httpAgent = new PacProxyAgent(options.proxy) @@ -206,7 +215,15 @@ const createRequest = (method, uri, data = {}, options) => { x.replace(/\s*Domain=[^(;|$)]+;*/, ''), ) try { - answer.body = JSON.parse(body.toString()) + if (data.e_r) { + // eapi接口返回值被加密 + answer.body = encrypt.eapiResDecrypt( + body.toString('hex').toUpperCase(), + ) + } else { + answer.body = JSON.parse(body.toString()) + } + if (answer.body.code) { answer.body.code = Number(answer.body.code) } @@ -221,13 +238,8 @@ const createRequest = (method, uri, data = {}, options) => { } } catch (e) { // console.log(e) - try { - answer.body = JSON.parse(encrypt.decrypt(body)) - } catch (err) { - // console.log(err) - // can't decrypt and can't parse directly - answer.body = body - } + // can't decrypt and can't parse directly + answer.body = body answer.status = res.status } From 8de3e9fa66ea3a4abd04243d2bab08afe9ac2a79 Mon Sep 17 00:00:00 2001 From: overwriter <9856mmm@gmail.com> Date: Sat, 13 Jul 2024 08:46:45 +0800 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20=E8=B0=83=E6=95=B4=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E8=AF=B7=E6=B1=82=E6=95=B0=E6=8D=AE=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=BB=93=E6=9E=84=EF=BC=9B=E6=B7=BB=E5=8A=A0=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/request.js | 153 ++++++++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 71 deletions(-) diff --git a/util/request.js b/util/request.js index 10b5997..319b04c 100644 --- a/util/request.js +++ b/util/request.js @@ -85,80 +85,91 @@ const createRequest = (method, uri, data = {}, options) => { } // console.log(options.cookie, headers['Cookie']) - let url = '' - let encryptData = '' - // 目前任意uri都支持三种加密方式 - if (options.crypto === 'weapi') { - headers['Referer'] = 'https://music.163.com' - headers['User-Agent'] = options.ua || chooseUserAgent('pc') - let csrfToken = (headers['Cookie'] || '').match(/_csrf=([^(;|$)]+)/) - data.csrf_token = csrfToken ? csrfToken[1] : '' - encryptData = encrypt.weapi(data) - url = APP_CONF.domain + '/weapi/' + uri.substr(5) - } else if (options.crypto === 'linuxapi') { - headers['User-Agent'] = - 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36' - encryptData = encrypt.linuxapi({ - method: method, - url: APP_CONF.apiDomain + uri, - params: data, - }) - url = 'https://music.163.com/api/linux/forward' - } else if ( - options.crypto === 'eapi' || - options.crypto === 'api' || - options.crypto === '' - ) { - // 两种加密方式,都应生成客户端的cookie - const cookie = options.cookie || {} - const csrfToken = cookie['__csrf'] || '' - const header = { - osver: cookie.osver || '17.4.1', //系统版本 - deviceId: cookie.deviceId || global.deviceId, - appver: cookie.appver || iosAppVersion, // app版本 - versioncode: cookie.versioncode || '140', //版本号 - mobilename: cookie.mobilename || '', //设备model - buildver: cookie.buildver || Date.now().toString().substr(0, 10), - resolution: cookie.resolution || '1920x1080', //设备分辨率 - __csrf: csrfToken, - os: cookie.os || 'ios', - channel: cookie.channel || '', - requestId: `${Date.now()}_${Math.floor(Math.random() * 1000) - .toString() - .padStart(4, '0')}`, - } - if (cookie.MUSIC_U) header['MUSIC_U'] = cookie.MUSIC_U - if (cookie.MUSIC_A) header['MUSIC_A'] = cookie.MUSIC_A - headers['Cookie'] = Object.keys(header) - .map( - (key) => - encodeURIComponent(key) + '=' + encodeURIComponent(header[key]), - ) - .join('; ') + let url = '', + encryptData = '', + crypto = options.crypto + // 根据加密方式加密请求数据;目前任意uri都支持四种加密方式 + switch (crypto) { + case 'weapi': + headers['Referer'] = 'https://music.163.com' + headers['User-Agent'] = options.ua || chooseUserAgent('pc') + let csrfTokenList = (headers['Cookie'] || '').match(/_csrf=([^(;|$)]+)/) + data.csrf_token = csrfTokenList ? csrfTokenList[1] : '' + encryptData = encrypt.weapi(data) + url = APP_CONF.domain + '/weapi/' + uri.substr(5) + break - let eapiEncrypt = () => { - data.header = header - encryptData = encrypt.eapi(uri, data) - url = APP_CONF.apiDomain + '/eapi/' + uri.substr(5) - data.e_r = data.e_r != undefined ? data.e_r : APP_CONF.encryptResponse // 用于加密eapi接口的返回值 - } - if (options.crypto === 'eapi') { - eapiEncrypt() - } else if (options.crypto === 'api') { - url = APP_CONF.apiDomain + uri - encryptData = data - } else if (options.crypto === '') { - // 加密方式为空,以配置文件的加密方式为准 - if (APP_CONF.encrypt) { - eapiEncrypt() - } else { + case 'linuxapi': + headers['User-Agent'] = + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36' + encryptData = encrypt.linuxapi({ + method: method, + url: APP_CONF.apiDomain + uri, + params: data, + }) + url = 'https://music.163.com/api/linux/forward' + break + + case 'eapi': + case 'api': + case '': + // 两种加密方式,都应生成客户端的cookie + const cookie = options.cookie || {} + const csrfToken = cookie['__csrf'] || '' + const header = { + osver: cookie.osver || '17.4.1', //系统版本 + deviceId: cookie.deviceId || global.deviceId, + appver: cookie.appver || iosAppVersion, // app版本 + versioncode: cookie.versioncode || '140', //版本号 + mobilename: cookie.mobilename || '', //设备model + buildver: cookie.buildver || Date.now().toString().substr(0, 10), + resolution: cookie.resolution || '1920x1080', //设备分辨率 + __csrf: csrfToken, + os: cookie.os || 'ios', + channel: cookie.channel || '', + requestId: `${Date.now()}_${Math.floor(Math.random() * 1000) + .toString() + .padStart(4, '0')}`, + } + if (cookie.MUSIC_U) header['MUSIC_U'] = cookie.MUSIC_U + if (cookie.MUSIC_A) header['MUSIC_A'] = cookie.MUSIC_A + headers['Cookie'] = Object.keys(header) + .map( + (key) => + encodeURIComponent(key) + '=' + encodeURIComponent(header[key]), + ) + .join('; ') + + let eapi = () => { + // 使用eapi加密 + data.header = header + encryptData = encrypt.eapi(uri, data) + url = APP_CONF.apiDomain + '/eapi/' + uri.substr(5) + data.e_r = data.e_r != undefined ? data.e_r : APP_CONF.encryptResponse // 用于加密接口返回值 + } + let api = () => { + // 不使用任何加密 url = APP_CONF.apiDomain + uri encryptData = data } - } - } else { - // 未知的加密方式 - console.log('[ERR]', 'Unknown Crypto:', options.crypto) + if (crypto === 'eapi') { + eapi() + } else if (crypto === 'api') { + api() + } else if (crypto === '') { + // 加密方式为空,以配置文件的加密方式为准 + if (APP_CONF.encrypt) { + eapi() + } else { + api() + } + } + break + + default: + // 未知的加密方式 + console.log('[ERR]', 'Unknown Crypto:', crypto) + break } const answer = { status: 500, body: {}, cookie: [] } // console.log(headers, 'headers') @@ -216,7 +227,7 @@ const createRequest = (method, uri, data = {}, options) => { ) try { if (data.e_r) { - // eapi接口返回值被加密 + // eapi接口返回值被加密,需要解密 answer.body = encrypt.eapiResDecrypt( body.toString('hex').toUpperCase(), ) From 83cc9a7566fc416776d91dee9fe49e3b1b43d0cd Mon Sep 17 00:00:00 2001 From: overwriter <9856mmm@gmail.com> Date: Sat, 13 Jul 2024 16:32:11 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=9A=20=E8=8E=B7=E5=8F=96=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E6=AD=8C=E6=9B=B2=E4=B8=8B=E8=BD=BD=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=20-=20=E6=96=B0=E7=89=88=E3=80=81=E5=BD=93=E5=89=8D=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E5=85=B3=E6=B3=A8=E7=9A=84=E7=94=A8=E6=88=B7/?= =?UTF-8?q?=E6=AD=8C=E6=89=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.MD | 3 +++ module/song_download_url_v1.js | 18 ++++++++++++++++++ module/user_follow_mixed.js | 24 ++++++++++++++++++++++++ public/docs/home.md | 29 +++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 module/song_download_url_v1.js create mode 100644 module/user_follow_mixed.js diff --git a/README.MD b/README.MD index a0768c0..6135715 100644 --- a/README.MD +++ b/README.MD @@ -426,6 +426,9 @@ banner({ type: 0 }).then((res) => { 280. 获取专辑歌曲的音质 281. 歌手动态信息 282. 最近听歌列表 +283. 云盘导入歌曲 +284. 获取客户端歌曲下载链接 - 新版 +285. 当前账号关注的用户/歌手 ## 单元测试 diff --git a/module/song_download_url_v1.js b/module/song_download_url_v1.js new file mode 100644 index 0000000..00bbaaf --- /dev/null +++ b/module/song_download_url_v1.js @@ -0,0 +1,18 @@ +// 获取客户端歌曲下载链接 - v1 +// 此版本不再采用 br 作为音质区分的标准 +// 而是采用 standard, exhigh, lossless, hires, jyeffect(高清环绕声), sky(沉浸环绕声), jymaster(超清母带) 进行音质判断 + +const createOption = require('../util/option.js') +module.exports = (query, request) => { + const data = { + id: query.id, + immerseType: 'c51', + level: query.level, + } + return request( + 'POST', + `/api/song/enhance/download/url/v1`, + data, + createOption(query), + ) +} diff --git a/module/user_follow_mixed.js b/module/user_follow_mixed.js new file mode 100644 index 0000000..eac883e --- /dev/null +++ b/module/user_follow_mixed.js @@ -0,0 +1,24 @@ +// 当前账号关注的用户/歌手 + +const createOption = require('../util/option.js') +module.exports = (query, request) => { + const size = query.size || 30 + const cursor = query.cursor || 0 + const scene = query.scene || 0 // 0: 所有关注 1: 关注的歌手 2: 关注的用户 + const data = { + authority: 'false', + page: JSON.stringify({ + size: size, + cursor: cursor, + }), + scene: scene, + size: size, + sortType: '0', + } + return request( + 'POST', + `/api/user/follow/users/mixed/get/v2`, + data, + createOption(query), + ) +} diff --git a/public/docs/home.md b/public/docs/home.md index 6677ace..ad2b56e 100644 --- a/public/docs/home.md +++ b/public/docs/home.md @@ -299,6 +299,8 @@ 281. 歌手动态信息 282. 最近听歌列表 283. 云盘导入歌曲 +284. 获取客户端歌曲下载链接 - 新版 +285. 当前账号关注的用户/歌手 ## 安装 @@ -4685,6 +4687,33 @@ bitrate = Math.floor(br / 1000) ``` 导入后的文件名后缀均为 `.mp3` 。但用 `获取音乐url` 获取到的文件格式仍然是正确的。 +### 获取客户端歌曲下载链接 - 新版 + +说明 : 使用 `/song/url/v1` 接口获取的是歌曲试听 url, 但存在部分歌曲在非 VIP 账号上可以下载无损音质而不能试听无损音质, 使用此接口可使非 VIP 账号获取这些歌曲的无损音频 + +**必选参数 :** `id` : 音乐 id + `level`: 播放音质等级, 分为 `standard` => `标准`,`higher` => `较高`, `exhigh`=>`极高`, +`lossless`=>`无损`, `hires`=>`Hi-Res`, `jyeffect` => `高清环绕声`, `sky` => `沉浸环绕声`, +`jymaster` => `超清母带` + +**接口地址 :** `/song/download/url/v1` + +**调用例子 :** `/song/download/url/v1?id=2058263032&level=lossless` + +### 当前账号关注的用户/歌手 + +说明 : 调用此接口, 可获得当前账号关注的用户/歌手 + +**可选参数 :** `size` : 返回数量 , 默认为 30 + +`cursor` : 返回数据的 cursor, 默认为 0 , 传入上一次返回结果的 cursor,将会返回下一页的数据 + +`scene` : 场景, 0 表示所有关注, 1 表示关注的歌手, 2 表示关注的用户, 默认为 0 + +**接口地址 :** `/user/follow/mixed` + +**调用例子 :** `/user/follow/mixed?scene=1` + ## 离线访问此文档 此文档同时也是 Progressive Web Apps(PWA), 加入了 serviceWorker, 可离线访问 From 02505b72d41fd08485f3e1c8f1ed8d043ab91be8 Mon Sep 17 00:00:00 2001 From: overwriter <9856mmm@gmail.com> Date: Sat, 13 Jul 2024 17:35:44 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20e=5Fr=E5=9C=A8=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E5=89=8D=E6=8F=92=E5=85=A5data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/option.js | 1 + util/request.js | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/util/option.js b/util/option.js index 3768ead..ae0bd2e 100644 --- a/util/option.js +++ b/util/option.js @@ -5,6 +5,7 @@ const createOption = (query, crypto = '') => { ua: query.ua || '', proxy: query.proxy, realIP: query.realIP, + e_r: query.e_r || undefined, } } module.exports = createOption diff --git a/util/request.js b/util/request.js index 319b04c..db13a3a 100644 --- a/util/request.js +++ b/util/request.js @@ -143,9 +143,14 @@ const createRequest = (method, uri, data = {}, options) => { let eapi = () => { // 使用eapi加密 data.header = header + data.e_r = + options.e_r != undefined + ? options.e_r + : data.e_r != undefined + ? data.e_r + : APP_CONF.encryptResponse // 用于加密接口返回值 encryptData = encrypt.eapi(uri, data) url = APP_CONF.apiDomain + '/eapi/' + uri.substr(5) - data.e_r = data.e_r != undefined ? data.e_r : APP_CONF.encryptResponse // 用于加密接口返回值 } let api = () => { // 不使用任何加密 @@ -232,7 +237,8 @@ const createRequest = (method, uri, data = {}, options) => { body.toString('hex').toUpperCase(), ) } else { - answer.body = JSON.parse(body.toString()) + answer.body = + typeof body == 'object' ? body : JSON.parse(body.toString()) } if (answer.body.code) { From 9310aa450af1e3f58ca729a326f96421f91b4c22 Mon Sep 17 00:00:00 2001 From: overwriter <9856mmm@gmail.com> Date: Sun, 14 Jul 2024 11:48:00 +0800 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20=E5=B0=86csrfToken=E6=8A=BD?= =?UTF-8?q?=E5=87=BA=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/request.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/util/request.js b/util/request.js index db13a3a..9bb6d06 100644 --- a/util/request.js +++ b/util/request.js @@ -87,14 +87,14 @@ const createRequest = (method, uri, data = {}, options) => { let url = '', encryptData = '', - crypto = options.crypto + crypto = options.crypto, + csrfToken = cookie['__csrf'] || '' // 根据加密方式加密请求数据;目前任意uri都支持四种加密方式 switch (crypto) { case 'weapi': headers['Referer'] = 'https://music.163.com' headers['User-Agent'] = options.ua || chooseUserAgent('pc') - let csrfTokenList = (headers['Cookie'] || '').match(/_csrf=([^(;|$)]+)/) - data.csrf_token = csrfTokenList ? csrfTokenList[1] : '' + data.csrf_token = csrfToken encryptData = encrypt.weapi(data) url = APP_CONF.domain + '/weapi/' + uri.substr(5) break @@ -115,7 +115,6 @@ const createRequest = (method, uri, data = {}, options) => { case '': // 两种加密方式,都应生成客户端的cookie const cookie = options.cookie || {} - const csrfToken = cookie['__csrf'] || '' const header = { osver: cookie.osver || '17.4.1', //系统版本 deviceId: cookie.deviceId || global.deviceId,