# 淘宝小程序 + Java + SAE 最小 MVP 操作步骤 > 目标:先用一个最小页面,把 **淘宝小程序 → 淘宝云网关(或本地直连)→ Java 后端 → 统一 envelope 返回** 这条链路跑通。 > > 本文不包含:真实测肤算法、Face++、账号体系、图片分片上传。这些等链路验证通过后,再按现有 Node 实现的接口契约迁到 Java。 > > 当前时间:2026-10。淘宝开放平台在 2026-05 把聚石塔的部署运维迁到了 ACK/SAE,网上 2023 年以前的“容器部署平台”教程不要照抄。 --- ## 0. 本次交付物 | 路径 | 作用 | |---|---| | `backend-java/` | Spring Boot 3.5.6 + Java 17 的最小后端,含 `ping/whoami/echo` | | `backend-java/src/main/java/com/juzi/mvp/gateway/TaobaoSignatureVerifier.java` | 云网关签名校验,算法与现有 Node 实现一致 | | `taobao/pages/mvp/` | 淘宝小程序连通性页面,直接复用现有 `utils/transport.js` | | `taobao/config.js` | 新增 `mvpLocal` / `mvpBaseUrl`,不影响主应用原来的 18180 配置 | | `taobao/app.json` | 注册 `pages/mvp/mvp` | | `tools/env-java.ps1` | 一键加载 JDK 17 + Maven 3.9.9 | | `backend-java/README.md` | 后端速查 | | `docs/SAE-Java-MVP-操作步骤.md` | 本文 | 现有 H5、Node 后端、淘宝主流程页面均未改动;只新增 MVP 页面和两个配置字段。 --- ## 1. 环境安装 本机已有: - Node.js `v22.23.2`:`C:\Program Files\nodejs` - JDK 17:`D:\juzi\tools\jdk17` - Maven 3.9.9:`D:\juzi\tools\maven\apache-maven-3.9.9` PowerShell 默认执行策略是 `Restricted`,直接运行 `.ps1` 或 `npm.ps1` 会被拦。每次新开窗口先执行: ```powershell Set-ExecutionPolicy -Scope Process Bypass . D:\juzi\tools\env-java.ps1 ``` 然后确认: ```powershell java -version mvn -version node -v npm.cmd -v ``` 预期: - `java version "17.x"` - `Apache Maven 3.9.9` - `v22.23.2` - `10.9.x` > 如果 `env-java.ps1` 报 “JDK 17 not found”,检查 `D:\juzi\tools\jdk17\\bin\java.exe` 是否存在;脚本会自动向下找一层目录。 > > 不要用系统里的 JDK 25 来跑这个 MVP;SAE 运行时选 17,编译也用 17,避免 `UnsupportedClassVersionError`。 --- ## 2. 后端本地启动 ```powershell Set-ExecutionPolicy -Scope Process Bypass . D:\juzi\tools\env-java.ps1 cd D:\juzi\backend-java mvn -DskipTests package java -jar target\taobao-mvp-backend-0.0.2.jar ``` 第一次 `mvn package` 会下载 Spring Boot 依赖,耐心等几分钟。看到类似日志即成功: ```text Tomcat started on port 8080 (http) Started MvpApplication in ... ``` 想跑自动化测试(签名算法 + envelope + health):`mvn test`。 ### 2.1 另开一个窗口验证 ```powershell curl.exe http://127.0.0.1:8080/actuator/health curl.exe -X POST -H "Content-Type: application/json" -d "{}" http://127.0.0.1:8080/api/taobao/ping Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8080/api/taobao/echo -ContentType 'application/json' -Body '{"hello":"world"}' | ConvertTo-Json -Depth 5 ``` > PowerShell 调原生 `curl.exe` 时,`-d` 里的双引号可能被吞掉(会看到 `{hello:world}` 解析失败);发 JSON 建议用 `Invoke-RestMethod`,或者把 body 写进文件后用 `--data-binary "@body.json"`。 预期 `ping`: ```json { "success": true, "data": { "ok": true, "pong": true, "server": "java", "time": "2026-10-30T...+08:00", "transport": "direct", "appKey": "", "openId": "", "env": "", "signVerified": false, "signMessage": "verify-sign=false, skipped (local/direct mode)" } } ``` `echo` 预期能看到 `body.hello = "world"`。 > 所有 `/api/taobao/**` 返回的都是云网关要求的 envelope;`/actuator/health` 是给 SAE 健康检查用的普通 JSON,不是 envelope。 ### 2.2 不装 IDE 也能跑的前端契约测试 ```powershell cd D:\juzi node taobao\scripts\mvp-local-check.cjs ``` 这个脚本用 Node 模拟 `my.request`,加载真实的 `taobao/utils/transport.js`,直连 8080,验证 `ping/echo/whoami` 和 `unwrap` 解包。预期输出 `PASS`,其中 `ping.server = "java"`。如果这里都不过,先别开 IDE。 --- ## 3. 前端本地联调(淘宝 IDE) ### 3.1 安装依赖 ```powershell cd D:\juzi\taobao npm.cmd ci ``` 如果 `npm.cmd` 不在 PATH,用全路径: ```powershell & "C:\Program Files\nodejs\npm.cmd" ci ``` `@tbmp/mp-cloud-sdk` 已经是 `1.5.10`,与当前 npm 最新版一致。 ### 3.2 IDE 导入与启动页 1. 打开淘宝小程序开发者工具,导入 `D:\juzi\taobao`。 2. 填入真实小程序 AppID(`mini.project.json` 里的 `appid` 也可以留空,以 IDE 设置为准)。 3. 工具 → 构建 npm(把 `node_modules` 构建成小程序可用的包)。 4. 本地 `mvpLocal: true` 时,启动页右上角会出现「SAE MVP 连通性」入口,点它即可进入;也可以把启动页临时设为 `pages/mvp/mvp`。 5. 用**桌面模拟器**跑;手机上的 `127.0.0.1` 指向手机自己,连不到你电脑。 ### 3.3 当前配置 `taobao/config.js` 新增了: ```js mvpLocal: true, mvpBaseUrl: 'http://127.0.0.1:8080', ``` `pages/mvp/mvp.js` 在 `onLoad` 时如果 `mvpLocal === true`,会临时把 `transport` 改成 `direct`、`baseUrl` 改成 `mvpBaseUrl`,离开页面时恢复。这样不会破坏主应用原来指向 `18180` 的 Node 后端配置。 进入页面后会自动调用一次 `/api/taobao/ping`,也可以点三个按钮: - `POST /api/taobao/ping` - `POST /api/taobao/whoami` - `POST /api/taobao/echo` 预期页面显示 `server: "java"`、`pong: true`。 > 如果 IDE 拦截 localhost 请求,打开 IDE 的“不校验合法域名”/“开发环境不校验请求域名”开关(不同版本叫法不同)。桌面模拟器一般可以直接访问回环地址。 ### 3.4 这一步验证了什么 - 小程序的 `utils/transport.js` 能走 `direct` 分支; - `my.request` 能发 `POST application/json`; - `transport.unwrap` 能正确解包 `{success,data}`; - Java 后端端口、路径、返回结构都对。 --- ## 4. 云端链路(SAE + 聚石塔云应用) ### 4.1 先理解三层关系 ```text 淘宝小程序 └─ @tbmp/mp-cloud-sdk └─ 淘宝云网关(校验 appkey/sign,注入 open_id/access_token) └─ 聚石塔云应用(应用/环境/流量接入) └─ SAE(真正的 Java 容器,跑 JAR) ``` - **SAE 只是算力层**,不是“建一个公网 URL 就能被小程序调用”。 - 小程序要调通,SAE 应用必须挂在**聚石塔云应用**下,或者走**空应用(不入塔)+ 域名白名单**。 - 2026-05-11 公告:原聚石塔“应用创建链路”2026-06-20 下线,部署运维迁到 ACK/SAE;聚石塔保留云应用管理、环境管理、流量接入。 - 参考:[迁移通知](https://api.alidayu.com/support/announcementDetail.htm?source=search&id=25839)、[新链路快速创建云应用](https://open.taobao.com/doc.htm?docId=122332&docType=1)、[云服务产品概述](https://miniapp.open.taobao.com/docV3.htm?docId=118541&docType=1)。 ### 4.2 构建 JAR ```powershell Set-ExecutionPolicy -Scope Process Bypass . D:\juzi\tools\env-java.ps1 cd D:\juzi\backend-java mvn -DskipTests clean package ``` 产物: ```text D:\juzi\backend-java\target\taobao-mvp-backend-0.0.2.jar ``` ### 4.3 SAE 创建应用 在 SAE 控制台“创建应用 → 代码包部署 → 设置代码包部署”里按下面选: | 配置项 | 选择 | |---|---| | 技术栈语言 | **Java** | | 代码包类型 | **JAR 包部署** | | 应用运行环境 | **标准 Java 应用运行环境** | | Java 环境 | **Open JDK 17** | | 文件上传方式 | 上传 JAR 包 | | 启动命令 | 默认 `java -jar` | | 应用端口 | **8080** | | 健康检查 | HTTP `GET /actuator/health`,期望 200 | | 实例数 | **2**(至少 2,避免单点) | | 时区 | **Asia/Shanghai** | | 地域/命名空间/VPC | 用聚石塔创建云应用时分配的那套,不要自己新建默认命名空间 | **不要选**: - WAR 包部署 - `apache-tomcat-*` - `EDAS-Container-*` - Open JDK 25 原因:WAR/Tomcat 是给外置 Tomcat 的老项目;EDAS-Container 是 HSF/Pandora Boot 专用;Open JDK 25 与 Spring Boot 3.5 的兼容性没有 17 稳。 环境变量(SAE → 应用设置 → 环境变量): ```text TAOBAO_APP_KEY=你的AppKey TAOBAO_APP_SECRET=你的AppSecret TAOBAO_VERIFY_SIGN=true ``` > `TAOBAO_APP_SECRET` 只能放服务端,绝不能进小程序代码或 `config.js`。 建议 JVM 参数(按实例规格调整,堆小于容器内存): ```text -Xms512m -Xmx1024m -Duser.timezone=Asia/Shanghai ``` ### 4.3.1 更新代码包(重新上传 JAR) 应用创建之后,更新 JAR 的入口: 1. SAE 应用 `nnn` → 右上角「部署应用」/「变更」→「代码包部署」→ 上传新 JAR → 确定 → 部署。 2. 如果右上角没有,左侧「变更记录」→「创建变更」→ 代码包部署。 3. 聚石塔资源视图偶尔不显示部署按钮,可直接用完整 SAE 控制台: ```text https://saenext.console.aliyun.com/cn-zhangjiakou/app-list/micro ``` 选 `my-namespace` → `nnn` → 部署应用。 每次上传的 JAR 文件名/版本要不同,SAE 才会当成一个新版本。`pom.xml` 的 `` 已改成 `0.0.2`,产物是: ```text taobao-mvp-backend-0.0.2.jar ``` SAE 部署页的「版本」可以填 `0.0.2` 或 `20261101-2`。不要重复上传同名同版本的包。 ### 4.4 流量接入 - 云应用走**内网私网 SLB**:聚石塔“流量接入”里绑定私网 SLB,后端端口 8080。 - 不要给云应用开公网入口;公网只用于你自己调试。 - 如果后端要调 TOP/奇门/外部 API,给 SAE 配 **NAT 网关或 EIP**,否则容器只入不出,调用会超时。 - 数据库在 RDS 时,把 SAE 的网段/安全组加进 RDS 白名单。 ### 4.5 聚石塔/开放平台关联 1. 聚石塔控制台 → 云应用 → 新建云应用(按 2026-05 新链路向导)。 2. 部署方式选 SAE;创建测试环境、正式环境。 3. 在 SAE 里把 JAR 部署到对应应用/环境。 4. 聚石塔 → 流量接入 → 绑定私网 SLB(测试/正式各一套,或共用一个正式 SLB)。 5. 开放平台控制台 → 云托管 → 关联云应用 → 选择你的云应用和对应 SLB。 6. 在“服务测试”里调用 `POST /api/taobao/ping`,确认返回 `success: true`。 7. 在 `taobao/config.js` 里把 `mvpLocal` 改成 `false`,并配置: ```js transport: 'cloud', baseUrl: 'https://你的HTTPS域名', cloudAppId: '控制台拿到的 cloudAppId', cloudEnv: 'test', // 先 test,验收后改 online ``` 8. 进入 `pages/mvp/mvp`,点 `ping`,看到 `transport: "gateway"`、`signVerified: true` 即通。 > 账号必须一致:创建云应用的聚石塔账号,要和开放平台小程序账号一致;子账号看不到云应用。小程序上线后默认云应用不能再改,选择时确认好。 ### 4.6 空应用(不入塔)作为备选 如果这个 SAE 应用不在聚石塔,不能直接“关联云应用”。只能走空应用: 1. 开放平台 → 云托管 → 云应用管理 → 新建空应用。 2. 关联一个**没有敏感数据权限**的 AppKey。 3. 设置域名白名单,提交审批(HTTPS、已备案域名)。 4. 调用时 `exts.domain` 传你的域名;现有 `transport.js` 已经会传 `domain: config.baseUrl`。 注意:现有 `transport.js` 的 cloud 分支还要求 `config.cloudAppId` 非空。如果空应用控制台没有给 cloudAppId,需要先把这行校验放宽(或暂时先用聚石塔云应用)。 空应用只适合内容/工具/轻服务;电商交易、用户敏感数据类大概率不适合,还是得入塔。 --- ## 5. 云网关接口契约(Java 后端必须遵守) 现有 Node 实现已经按这个契约写了,Java 迁移时照抄: ```json { "success": true, "data": {}, "errorCode": "xxxx", "errorMessage": "xxxx" } ``` - 只支持 **GET/POST**;POST 必须 `application/json`。 - 请求体 **≤128KB**;超时默认 3s、最大 10s。 - 平台会往 URL 追加 `app_key`、`open_id`、`access_token`、`sign`、`env`、`mini_app_id` 等系统参数;自定义参数不要重名。 - 成功时小程序 SDK 只把 `data` 返回给页面;`errorCode/errorMessage` 在失败时返回。 - 发布前把 `cloudEnv` 从 `test` 改成 `online`;默认云应用上线后不能改。 - 图片/长任务不要塞进一个请求:现有实现是 64KiB 分片上传 + 异步任务 + 轮询。 参考:[云应用调用](https://open.m.taobao.com/docs/doc.htm?treeId=622&articleId=118538&docType=1)。 --- ## 6. 签名校验 Java 的 `TaobaoSignatureVerifier` 与现有 `h5/lib/taobao-auth.js` 算法一致: 1. 取全部 query 参数,排除 `sign` 和空值,按 key 升序,拼成 `key1value1key2value2...`。 2. 末尾追加**原始 JSON body**(不要重新序列化)。 3. `sign_method=md5`:`MD5(secret + content + secret)`;`sign_method` 为空:`MD5(content + secret)`;`hmac*` 用 HMAC。 4. 结果转大写十六进制,与 `sign` 比较。 本地 `TAOBAO_VERIFY_SIGN=false`,没有 `app_key/sign`,直接放行,返回 `signVerified:false`。 云端 `TAOBAO_VERIFY_SIGN=true`: - `app_key` 必须等于 `TAOBAO_APP_KEY`; - `open_id` 必须符合 `[A-Za-z0-9_-]{4,256}`; - `sign` 必须是 32–64 位十六进制; - 重复 query 参数直接拒绝; - 校验失败返回 `success:false, errorCode:"SIGN_INVALID"`。 如果云端一直 `SIGN_INVALID`,按顺序查: 1. SAE 环境变量是否真的注入(重启后生效)。 2. `TAOBAO_APP_KEY` 是否和云应用/小程序一致。 3. 网关用的 `sign_method` 与后端是否匹配。 4. body 是否被反向代理/框架重新序列化(必须保留原始字节)。 5. 是否有重复的 `open_id`/`app_key` 参数。 --- ## 7. 常见问题 | 现象 | 排查 | |---|---| | `UnsupportedClassVersionError` | 编译 JDK 高于 SAE 运行时;统一用 17 | | `404` | 路径不对;云应用 path 是否带 `/api/taobao`;WAR 的 context path | | `502/504` | SAE 端口不是 8080、健康检查失败、SLB 后端端口不对 | | `success:false` + `SIGN_INVALID` | 见第 6 节 | | `cloud init failed` | IDE 未登录、AppID/cloudAppId 不匹配、cloudEnv 不对 | | `请先配置淘宝云应用和 HTTPS 服务地址` | `transport:'cloud'` 但 `baseUrl` 不是 HTTPS 或 `cloudAppId` 为空 | | `直连接口仅用于本机联调` | `transport:'direct'` 但 `baseUrl` 不是 localhost/127.0.0.1 | | `Cannot find module '@tbmp/mp-cloud-sdk'` | `npm.cmd ci` 后,在 IDE 里执行“构建 npm” | | 手机真机请求失败 | 127.0.0.1 是手机自己;真机必须走云端 HTTPS | | 请求超过 10 秒 | 云网关最大 10s;改异步任务 + 轮询 | | 返回体超过 128KB | 分页/裁剪字段,不要把大图 base64 放进响应 | ### 7.1 淘宝 IDE 报 `install miniapp extension fail: ... wmic ...` Windows 11 24H2 起默认移除了 `wmic.exe`,而淘宝开发者工具在安装小程序扩展时会执行: ```text wmic path win32_VideoController get caption ``` 找不到 `wmic` 就报这个错。本机已经放了一个兼容 shim: ```text C:\Users\youmi\.local\bin\wmic.cmd ``` 修复步骤: 1. 完全退出淘宝开发者工具(任务管理器里不要留 `淘宝开发者工具.exe`)。 2. 重新打开 IDE,再导入 `D:\juzi\taobao`。 如果 shim 丢了,重新运行: ```powershell powershell -ExecutionPolicy Bypass -File D:\juzi\tools\fix-taobao-ide-wmic.ps1 ``` 永久方案(需要管理员 PowerShell): ```powershell DISM /Online /Add-Capability /CapabilityName:WMIC~~~~ ``` 装完后 `C:\Windows\System32\wmic.exe` 会优先于 shim,shim 可以删除。如果 DISM 提示找不到这个能力,说明系统镜像没带 WMIC FoD,继续用 shim 即可。 --- ## 8. 下一步(MVP 通过后) 1. 把 `h5/lib/taobao-routes.js` 的接口逐个迁到 Java: - `POST /api/taobao/challenge` - `POST /api/taobao/session` - `POST /api/taobao/me` - `POST /api/taobao/photo`(64KiB 分片) - `POST /api/taobao/skin-analyze`(异步任务) - `POST /api/taobao/analysis`(轮询) - `POST /api/taobao/reports` - `POST /api/taobao/logout` 2. 所有 `/api/taobao/**` 统一走签名校验 + envelope。 3. 账号/历史/图片存到 RDS/OSS,不要放容器本地磁盘。 4. 保留 H5 的 Node 路由不变,淘宝走 Java;两边共用同一套业务规则时,先以现有 Node 实现为契约。 5. 接 SLS 日志、Actuator 健康检查、告警,再切正式流量。 --- ## 9. 命令速查 ```powershell # 每个新窗口 Set-ExecutionPolicy -Scope Process Bypass . D:\juzi\tools\env-java.ps1 # 后端 cd D:\juzi\backend-java mvn -DskipTests clean package java -jar target\taobao-mvp-backend-0.0.2.jar # 本地验证 curl.exe http://127.0.0.1:8080/actuator/health curl.exe -X POST -H "Content-Type: application/json" -d "{}" http://127.0.0.1:8080/api/taobao/ping # 前端依赖 cd D:\juzi\taobao npm.cmd ci ```