1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/55RK8C若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/55RK8C若失效,可用地址
https://www.aliyun.com/daily-act/ecs/activity_selection?source=5176.29345612&userCode=49hts92d腾讯云:
https://curl.qcloud.com/wJpWmSfU若失效,可用地址
https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=ad201ee2ef3b771157f72ee5464b1fea&from=console华为云
https://activity.huaweicloud.com/cps.html?fromacct=64b5cf7cc11b4840bb4ed2ea0b2f4468&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=2019052.部署教程
3.代码如下
// ==================== 配置区域 ====================const CONFIG = {// 基础URL - 蔚来签到接口地址baseURL: "https://gateway-front-external.nio.com",// APP信息appId: "10086",// User-Agent - 模拟蔚来APP的webviewuserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 NIOAppCN/5.48.5 (com.do1.WeiLaiApp; build:2549; OS:iOS) webview/lg _dsbridge",// 重试配置maxRetries: 3,retryDelay: 2000, // 重试间隔(毫秒)// Token管理配置tokenStorageKey: "weilai_auth_token",lastUpdateKey: "weilai_token_last_update",tokenValidDays: 30,// 拦截配置targetDomains: ["gateway-front-external.nio.com","app.nio.com","api.nio.com"],targetPaths: ["/checkin","/award","/user","/profile","/api"]};// ==================== Token管理模块 ====================// 检查URL是否需要拦截function shouldInterceptRequest(url) {try {const urlObj = new URL(url);// 检查域名const domainMatch = CONFIG.targetDomains.some(domain =>urlObj.hostname.includes(domain));if (!domainMatch) return false;// 检查路径const pathMatch = CONFIG.targetPaths.some(path =>urlObj.pathname.includes(path));return pathMatch;} catch (e) {console.log("❌ URL解析失败:", e);return false;}}// 提取Authorization tokenfunction extractToken(headers) {const authHeader = headers['authorization'] || headers['Authorization'];if (!authHeader) return null;// 验证token格式if (authHeader.startsWith('Bearer ') && authHeader.length > 20) {return authHeader;}return null;}// 保存token到本地存储function saveToken(token) {const currentTime = Date.now();try {// 保存token$persistentStore.write(token, CONFIG.tokenStorageKey);// 保存更新时间$persistentStore.write(currentTime.toString(), CONFIG.lastUpdateKey);console.log("✅ Token已自动保存");console.log(`🔑 Token: ${token.substring(0, 20)}...`);console.log(`📅 保存时间: ${new Date(currentTime).toLocaleString('zh-CN')}`);return true;} catch (e) {console.log("❌ Token保存失败:", e);return false;}}// 获取已保存的tokenfunction getSavedToken() {try {const token = $persistentStore.read(CONFIG.tokenStorageKey);const lastUpdate = $persistentStore.read(CONFIG.lastUpdateKey);if (!token || !lastUpdate) return null;const lastUpdateTime = parseInt(lastUpdate);const isExpired = isTokenExpired(lastUpdateTime);return {token: token,lastUpdate: lastUpdateTime,isExpired: isExpired};} catch (e) {console.log("❌ Token读取失败:", e);return null;}}// 检查token是否过期function isTokenExpired(lastUpdate) {const now = Date.now();const expireTime = lastUpdate + (CONFIG.tokenValidDays * 24 * 60 * 60 * 1000);return now > expireTime;}// 获取有效的tokenfunction getValidToken() {const tokenInfo = getSavedToken();if (!tokenInfo) {console.log("❌ 未找到保存的token");return null;}if (tokenInfo.isExpired) {console.log("⚠️ Token已过期,需要重新抓取");$notification.post("蔚来签到", "Token已过期 ⏰", "请在蔚来APP中进行操作以更新token");return null;}console.log("✅ 获取到有效token");const remainingDays = Math.ceil((tokenInfo.lastUpdate + CONFIG.tokenValidDays * 24 * 60 * 60 * 1000 - Date.now()) / (24 * 60 * 60 * 1000));console.log(`⏰ Token剩余有效期: ${remainingDays} 天`);return tokenInfo.token;}// Token拦截处理函数function handleTokenCapture(request) {const url = request.url;const headers = request.headers;console.log(`🔍 拦截到请求: ${url}`);// 检查是否需要拦截if (!shouldInterceptRequest(url)) {console.log("⏭️ 跳过此请求");return;}// 提取tokenconst token = extractToken(headers);if (!token) {console.log("❌ 未找到有效的Authorization token");return;}// 检查是否是新tokenconst savedTokenInfo = getSavedToken();if (savedTokenInfo && savedTokenInfo.token === token && !savedTokenInfo.isExpired) {console.log("ℹ️ Token未变化且未过期,跳过保存");return;}// 保存新tokenif (saveToken(token)) {const message = savedTokenInfo ? "Token已自动更新" : "Token已自动获取";$notification.post("蔚来Token", message + " 🔑", "签到脚本将自动使用新token");}}// ==================== 工具函数 ====================// 格式化日期时间function formatDateTime(timestamp) {const date = new Date(timestamp * 1000);return date.toLocaleString('zh-CN', {year: 'numeric',month: '2-digit',day: '2-digit',hour: '2-digit',minute: '2-digit',second: '2-digit'});}// ==================== 签到功能模块 ====================// 生成请求参数function buildParams() {const timestamp = Date.now();return {app_id: CONFIG.appId,timestamp: timestamp};}// 构建请求URLfunction buildURL(params) {const queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');return `${CONFIG.baseURL}/moat/10086/c/award_cn/checkin?${queryString}`;}// 构建请求头function buildHeaders(token) {return {"authority": "gateway-front-external.nio.com","content-type": "application/x-www-form-urlencoded","accept": "application/json, text/plain, */*","authorization": token,"sec-fetch-site": "cross-site","priority": "u=3, i","accept-language": "zh-CN,zh-Hans;q=0.9","accept-encoding": "gzip, deflate, br","sec-fetch-mode": "cors","origin": "null","user-agent": CONFIG.userAgent,"sec-fetch-dest": "empty"};}// 处理签到响应function handleResponse(response, data) {try {const result = JSON.parse(data);// 检查签到结果if (response.status === 200 && result.result_code === 'success') {const stats = result.data?.stats || {};const tip = result.data?.tip || "签到完成";const continuousDays = stats.continuous_checkin_days || 0;const accumulateDays = stats.accumulate_days || 0;const checkinTime = stats.checkin_time ? formatDateTime(stats.checkin_time) : '';console.log("✅ 签到成功!");console.log(`📅 签到时间: ${checkinTime}`);console.log(`🔥 连续签到: ${continuousDays} 天`);console.log(`📊 累计签到: ${accumulateDays} 天`);const message = `${tip}\n📊 累计签到: ${accumulateDays} 天`;$notification.post("蔚来签到", "签到成功 🎉", message);return { success: true, message: tip };} else if (result.data?.checked_in === true) {const tip = result.data?.tip || "今日已签到";console.log("ℹ️ 今日已签到");console.log(`💡 提示: ${tip}`);$notification.post("蔚来签到", "今日已签到 ✅", tip);return { success: true, message: tip };} else {const errorMsg = result.message || result.error || "签到失败";console.log("❌ 签到失败:", result);$notification.post("蔚来签到", "签到失败 ❌", errorMsg);return { success: false, message: errorMsg };}} catch (e) {console.log("❌ 解析响应失败:", e);console.log("📄 原始响应:", data);$notification.post("蔚来签到", "解析失败 ⚠️", "响应格式异常");return { success: false, message: "响应解析异常" };}}// 执行签到请求 (支持重试)function performCheckin(token, retryCount = 0) {const params = buildParams();const url = buildURL(params);const headers = buildHeaders(token);const body = "event=checkin";const request = {url: url,method: "POST",headers: headers,body: body};console.log(`🚗 开始蔚来签到... (尝试 ${retryCount + 1}/${CONFIG.maxRetries + 1})`);console.log(`📡 请求URL: ${url}`);$httpClient.post(request, (error, response, data) => {if (error) {console.log(`❌ 网络请求失败 (尝试 ${retryCount + 1}):`, error);// 重试逻辑if (retryCount < CONFIG.maxRetries) {console.log(`⏳ ${CONFIG.retryDelay/1000}秒后重试...`);setTimeout(() => {performCheckin(token, retryCount + 1);}, CONFIG.retryDelay);return;} else {console.log("❌ 达到最大重试次数,签到失败");$notification.post("蔚来签到", "网络错误 🌐", `请求失败: ${error}`);$done();return;}}console.log(`📊 响应状态码: ${response.status}`);console.log(`📄 响应数据长度: ${data ? data.length : 0} 字节`);const result = handleResponse(response, data);if (!result.success && retryCount < CONFIG.maxRetries) {console.log(`⏳ ${CONFIG.retryDelay/1000}秒后重试...`);setTimeout(() => {performCheckin(token, retryCount + 1);}, CONFIG.retryDelay);} else {$done();}});}// ==================== 主函数 ====================// 脚本入口function main() {// 如果是HTTP请求拦截模式if (typeof $request !== 'undefined' && $request) {console.log("🎯 Token拦截模式启动");handleTokenCapture($request);$done({});return;}// 如果是签到模式console.log("🔄 蔚来全自动签到脚本启动");console.log(`📅 当前时间: ${new Date().toLocaleString('zh-CN')}`);console.log(`🔧 脚本版本: v2.0.0 (融合版)`);console.log(`🌐 请求域名: ${CONFIG.baseURL}`);// 获取有效tokenconst token = getValidToken();if (!token) {console.log("❌ 无法获取有效token,请在蔚来APP中进行操作");$notification.post("蔚来签到", "Token获取失败 🔑", "请打开蔚来APP进行任意操作以自动获取token");$done();return;}console.log("✅ Token验证通过,开始签到");// 开始签到performCheckin(token);}// 执行脚本main();
这是融合版蔚来 App 自动签到脚本,把两个场景合在一个脚本里:
抓 token(拦截模式)
当拦截到蔚来 App 的某些请求时,从请求头里提取Authorization: Bearer ...,并写入的持久化存储($persistentStore),同时记录更新时间。用 token 自动签到(定时模式)
定时运行时从本地读取 token,判断是否过期,然后调用蔚来签到接口:POST /moat/10086/c/award_cn/checkin?...
成功后通知:显示签到提示、连续天数、累计天数等。
此外它还包含:
Token 过期提醒(按 "保存后 30 天" 的逻辑判断)
失败重试(网络失败或业务失败可重试)
通知推送(
$notification.post)
主要方法
1)拦截 & Token 管理相关
shouldInterceptRequest(url)
作用:判断某个请求 URL 是否属于"需要抓 token 的目标请求"。
逻辑:检查域名是否命中
CONFIG.targetDomains,路径是否包含CONFIG.targetPaths。
extractToken(headers)
作用:从请求头中提取
Authorization。逻辑:只接受
Bearer开头且长度较长的值,避免误判。
saveToken(token)
作用:把 token 和"保存时间"写入本地存储。
存储键:
token:
CONFIG.tokenStorageKey时间:
CONFIG.lastUpdateKey
getSavedToken()
作用:读取已保存的 token + 更新时间,并计算是否过期。
返回结构:
{ token, lastUpdate, isExpired }
isTokenExpired(lastUpdate)
作用:按照
tokenValidDays(默认 30 天)判断 token 是否过期。
getValidToken()
作用:给"签到模块"提供可用 token。
行为:
没有 token → 返回 null
token 过期 → 弹通知提醒去 App 触发更新,并返回 null
token 可用 → 返回 token
handleTokenCapture(request)
作用:拦截模式的入口函数。
流程:
判断是否命中拦截范围
提取 token
与已保存 token 对比(没变化且未过期就不保存)
保存并通知
2)签到请求构建与执行相关
buildParams()
作用:生成签到接口需要的 query 参数(
app_id、timestamp)。
buildURL(params)
作用:把参数拼成最终签到 URL。
最终形式:
https://gateway-front-external.nio.com/moat/10086/c/award_cn/checkin?...
buildHeaders(token)
作用:构建签到请求头(核心是带上
authorization: token和模拟 App UA)。
handleResponse(response, data)
作用:解析接口返回 JSON,并区分三类结果:
签到成功:
status=200 && result_code='success',提取连续天数、累计天数、签到时间等并通知今日已签到:
data.checked_in === true(或类似结构)签到失败:其他情况,取
message/error作为失败原因通知输出:
{ success: boolean, message: string }
performCheckin(token, retryCount=0)
作用:真正发起 HTTP 请求并实现重试机制。
特点:
使用
$httpClient.post网络 error 或业务失败可按
maxRetries重试最终调用
$done()结束 脚本运行
3)入口控制
main()
作用:脚本"融合"的关键入口,自动识别运行场景:
如果存在
$request→ 拦截模式(抓 token)否则 → 定时签到模式(取 token → 签到 → 通知)
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论