多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

AutoJsPro自建服务器:脚本分发与授权校验实战

AutoJsPro自建服务器:脚本分发与授权校验实战 简介这份资源面向希望为 AutoJsPro 搭建私有服务器、实现远程控制等高级自动化功能的 Android 脚本开发者尤其适合具备一定 Node.js 与网络基础的中级用户。压缩包共 9 个文件约 344.42MB涵盖 apk 安装包、mp4 视频教程、txt 文字教程、json 配置、exe 服务端程序及 hosts 文件等分别用于客户端安装、服务端部署与网络代理配置。教程以视频与文本双形式讲解 Node.js 环境搭建、ProxyPin 代理设置及 Python 辅助脚本的配合使用帮助读者理解服务器配置与通信流程。目前已有 13612 人学习下载内容覆盖网络编程、系统配置与安全设置等多个环节可帮助读者按步骤完成自建服务器并增强 AutoJsPro 的自动化能力。1. AutoJsPro 自建服务器把脚本仓库和授权校验握在自己手里如果你用 AutoJsPro 或 AutoX 写过自动化脚本大概率遇到过这个场景换台设备辛辛苦苦攒的脚本全得重新拷一遍团队协作时谁改了哪一版根本说不清想给脚本加个授权校验又不想把判断逻辑硬编码在客户端里被人反编译。这些问题的根子在于——你缺一台自己的服务器。AutoJsPro 自建服务器就是干这个的用一台你能控制的机器跑一个轻量服务端把脚本分发、版本管理、授权校验这些事从客户端挪到服务端。它适合手里有多个脚本项目、需要跨设备同步、或者要给脚本做简单授权控制的从业者。下面我从服务端怎么搭、客户端怎么连、坑在哪一步步拆开讲。2. 服务端选型与部署为什么用 Node.js 而不是 PHP2.1 选型逻辑脚本分发场景对服务端的真实要求AutoJsPro 自建服务器的核心需求其实很朴素提供 HTTP 接口让客户端拉取脚本列表和脚本内容附带一个简单的鉴权头校验。它不需要高并发不需要复杂 ORM甚至不需要数据库——脚本文件直接放磁盘元信息用一个 JSON 文件维护就够。那为什么常见做法是 Node.js 而不是 PHP因为 AutoJsPro 客户端发起请求时默认的 User-Agent 和请求头格式跟 Node 的 http 模块配合最顺PHP 的某些默认配置会对请求体做额外转义导致脚本里的特殊字符比如正则中的反斜杠在传输后被破坏。我一般会选 Node.js Express代码量少调试直观出问题看日志一眼能定位。另一个选型点是端口。AutoJsPro 客户端默认走 HTTP 而不是 HTTPS因为脚本分发场景通常在内网或受信任网络里跑上 TLS 反而增加证书配置成本。常见做法是服务端监听 8080 或 3000客户端填http://你的IP:端口。如果你非要走公网至少加一个自定义请求头做简单校验别裸奔。2.2 从零搭一个最小可用服务端先建目录初始化项目装 Expressmkdir autojs-server cd autojs-server npm init -y npm install express mkdir scripts然后在项目根目录建server.jsconst express require(express); const fs require(fs); const path require(path); const app express(); const PORT 3000; // 简单鉴权客户端请求头必须带 x-auth-token const AUTH_TOKEN your-secret-token-change-me; app.use((req, res, next) { const token req.headers[x-auth-token]; if (token ! AUTH_TOKEN) { return res.status(401).json({ code: 401, msg: unauthorized }); } next(); }); // 脚本列表接口返回 scripts 目录下所有 .js 文件的元信息 app.get(/api/list, (req, res) { const dir path.join(__dirname, scripts); const files fs.readdirSync(dir).filter(f f.endsWith(.js)); const list files.map(f { const stat fs.statSync(path.join(dir, f)); return { name: f, size: stat.size, mtime: stat.mtimeMs }; }); res.json({ code: 0, data: list }); }); // 脚本内容接口按文件名返回脚本正文 app.get(/api/script/:name, (req, res) { const filePath path.join(__dirname, scripts, req.params.name); if (!fs.existsSync(filePath)) { return res.status(404).json({ code: 404, msg: not found }); } const content fs.readFileSync(filePath, utf-8); res.json({ code: 0, data: content }); }); app.listen(PORT, () { console.log(AutoJsPro server running on port ${PORT}); });这段代码的逻辑很直白中间件做全局鉴权两个 GET 接口分别返回列表和内容。参数说明——AUTH_TOKEN是你自己定的字符串客户端请求时必须带同样的值PORT按需改只要客户端能访问到就行。启动命令是node server.js跑起来后先用浏览器或 curl 测一下curl -H x-auth-token: your-secret-token-change-me http://127.0.0.1:3000/api/list返回 JSON 里能看到 scripts 目录下的文件列表说明服务端通了。这一步别跳过很多后续问题其实是服务端根本没起来。2.3 脚本目录的组织方式与版本管理scripts目录直接放.js文件文件名就是脚本标识。但实际用起来你会发现一个问题同名脚本更新后客户端怎么知道该不该重新拉常见做法是在列表接口里带上mtime最后修改时间客户端本地缓存一份对比时间戳决定是否重新下载。如果你需要更正式的版本管理可以在文件名里带版本号比如task-v1.2.js列表接口按文件名排序返回客户端取最新版本。我一般会再加一个meta.json记录每个脚本的版本号和更新说明但这不是必须的看你的协作复杂度。注意脚本文件里如果有中文确保服务端读取时用utf-8编码否则客户端拿到的是乱码。上面代码里readFileSync已经指定了编码别漏。3. AutoJsPro 客户端对接请求封装与脚本热更新3.1 客户端请求脚本列表并下载AutoJsPro 里发 HTTP 请求用http.get或http.post但要注意它默认是异步回调风格。下面这段代码放在脚本开头作用是拉取服务端列表对比本地缓存下载新增或有更新的脚本// 服务端地址和鉴权 token跟服务端保持一致 const SERVER http://192.168.1.100:3000; const TOKEN your-secret-token-change-me; const CACHE_DIR /sdcard/autojs_cache/; // 确保缓存目录存在 files.ensureDir(CACHE_DIR); function fetchList() { const res http.get(SERVER /api/list, { headers: { x-auth-token: TOKEN } }); if (res.statusCode ! 200) { toast(列表拉取失败: res.statusCode); return []; } const body res.body.json(); return body.data || []; } function downloadScript(name) { const res http.get(SERVER /api/script/ name, { headers: { x-auth-token: TOKEN } }); if (res.statusCode ! 200) { toast(下载失败: name); return false; } const content res.body.json().data; files.write(CACHE_DIR name, content); return true; } // 主流程对比 mtime只下载有变化的 const remoteList fetchList(); remoteList.forEach(item { const localPath CACHE_DIR item.name; const localExists files.exists(localPath); if (!localExists) { downloadScript(item.name); toast(新增: item.name); } else { const localTime files.getLastModified(localPath); if (item.mtime localTime) { downloadScript(item.name); toast(更新: item.name); } } });逻辑说明fetchList拿服务端列表downloadScript按文件名拉内容并写入本地缓存目录。主流程遍历列表本地不存在就下载存在但服务端mtime更大就覆盖。参数方面——SERVER换成你服务端的实际 IP 和端口TOKEN跟服务端一致CACHE_DIR按你设备存储路径改。这段代码跑通后你每次执行它就能把服务端最新脚本同步到本地。3.2 脚本热更新与执行隔离下载到本地只是第一步真正跑起来还要解决执行隔离。AutoJsPro 里可以用engines.execScriptFile执行本地脚本文件但直接执行会共享全局变量多个脚本之间可能互相污染。常见做法是每个脚本用独立引擎执行function runScript(name) { const scriptPath CACHE_DIR name; if (!files.exists(scriptPath)) { toast(脚本不存在: name); return; } const engine engines.execScriptFile(scriptPath, { path: CACHE_DIR // 指定工作目录让脚本内的相对路径正确 }); // 可选监听执行结束 engine.on(exit, () { console.log(name 执行结束); }); }engines.execScriptFile的第二个参数是配置对象path指定工作目录这样脚本里用相对路径读写文件时不会跑到别的地方。如果你需要传参可以在执行前把参数写到临时文件脚本内再读——AutoJsPro 的引擎参数传递不如 Node 灵活这是常见绕法。3.3 授权校验的客户端侧配合服务端的鉴权头只是第一层。如果你要做更细的授权比如某个脚本只允许特定设备运行可以在服务端加一个/api/auth接口客户端启动时先请求校验服务端根据设备 ID 返回是否放行。设备 ID 可以用device.getAndroidId()获取客户端把它作为参数传给服务端。服务端维护一个白名单 JSON匹配就返回{ code: 0 }否则返回{ code: 403 }。客户端拿到 403 就停止执行并提示。这套逻辑不复杂但能挡住大部分直接拷贝脚本文件的行为。提示设备 ID 在恢复出厂设置后会变如果你的授权是长期绑定的记得在服务端留一个手动更新白名单的入口否则用户换机后你得改代码。4. 避坑与排查自建服务器最容易翻车的五个点4.1 客户端请求超时但服务端日志无记录现象AutoJsPro 里请求一直转圈最后报 timeout但服务端控制台没有任何请求日志。原因通常是客户端和服务端不在同一网段或者服务端防火墙拦了端口。解决先在客户端设备上用浏览器访问http://服务端IP:端口/api/list如果浏览器也打不开说明网络层不通检查 IP 是否写错、服务端是否监听在0.0.0.0而不是127.0.0.1。Express 的app.listen(PORT)默认监听所有网卡但如果你写了app.listen(PORT, 127.0.0.1)就只允许本机访问客户端连不上。4.2 脚本内容里的反斜杠被吞掉现象服务端返回的脚本内容里正则表达式\d变成d导致脚本执行报错。原因通常是中间件对响应体做了转义或者客户端res.body.json()解析时把反斜杠当转义符处理了。解决服务端返回 JSON 时用JSON.stringify自动处理转义客户端用res.body.json()而不是res.body.string()再手动解析。如果还有问题在服务端把脚本内容做一次 base64 编码客户端解码后再用这样能彻底避开转义问题。4.3 多设备同时下载导致文件写入冲突现象两台设备同时请求同一个脚本服务端readFileSync报EBUSY或客户端写入时文件损坏。原因Node.js 的readFileSync在文件被其他进程占用时会抛异常虽然概率低但多设备高频请求时可能触发。解决服务端读取文件时加 try-catch失败就重试一次客户端写入时先写临时文件再重命名避免半截文件被读到。更稳妥的做法是服务端启动时把脚本内容全部读进内存缓存后续请求直接返回内存数据既快又避免文件锁。4.4 鉴权 token 硬编码在客户端被提取现象你给脚本加了 token 校验但别人反编译客户端脚本后拿到了 token直接调你的接口。原因token 写在客户端脚本里AutoJsPro 的脚本虽然打包后不易读但并非不可逆。解决token 不要用固定值改成服务端下发临时 token——客户端先用设备 ID 换一个有效期 5 分钟的 token再用这个 token 请求脚本。这样即使被提取过期后也失效。实现上服务端加一个/api/token接口用内存 Map 存设备 ID 和过期时间即可。4.5 服务端重启后客户端缓存全部失效现象服务端重启mtime因为文件系统原因变了客户端认为所有脚本都更新了全部重新下载。原因某些文件系统在重启后mtime精度或时区处理不一致。解决不要依赖文件系统的mtime在meta.json里手动维护每个脚本的版本号列表接口返回版本号而不是mtime客户端对比版本号决定是否更新。版本号用递增整数或日期字符串都行关键是可控。5. 进阶用 RustDesk 思路做内网穿透式的脚本分发前面讲的都是内网场景。如果你需要跨网络访问自己的 AutoJsPro 服务器又不想把服务端暴露在公网可以借鉴 RustDesk 自建服务器的思路——在两端各跑一个轻量中转服务端只监听本地中转负责转发请求。具体做法在一台有公网 IP 的机器上跑一个 TCP 转发比如用socat或 Node 的net模块把公网端口映射到内网服务端的 3000 端口。客户端填公网 IP 和转发端口请求经过中转到达内网服务端。这样服务端本身不直接暴露安全边界更清晰。# 在公网机器上用 socat 做 TCP 转发 socat TCP-LISTEN:8080,fork,reuseaddr TCP:内网服务端IP:3000这条命令的意思是公网机器监听 8080收到连接后转发到内网服务端的 3000 端口。fork表示每个连接开一个子进程reuseaddr允许端口快速重用。客户端把SERVER改成http://公网IP:8080即可。注意 socat 本身不做鉴权你的x-auth-token仍然是唯一防线所以 token 别设太简单。验证方法在客户端设备上用http.get请求/api/list看返回的 JSON 里code是否为 0。如果返回 401说明 token 没带对如果超时检查 socat 进程是否在跑、公网防火墙是否放行 8080。我一般会在服务端加一行日志每次请求打印客户端 IP 和请求路径这样排查时一眼能看出请求到底有没有到达服务端。从那以后我每次搭这类分发服务都会先把鉴权中间件和日志中间件写好再写业务接口——血泪经验是没有日志的自建服务器就是个黑匣子出问题只能靠猜。希望帮到你。本文还有配套的精品资源点击获取
返回列表