KEC 微信小程序端 可行性评估报告
评估日期:2026-08-09 | 评估对象:kec-manager v1.0.2 约束条件:不改动现有 Web 前端与后端逻辑;目标产物为小程序体验版(不追求正式上线)
〇、总体结论
方案可行,且比预想的顺利——现有后端在"非浏览器客户端"场景下的兼容性意外地好,核心链路已实测跑通,无需改动一行后端代码。
但有 3 个门槛必须提前知道:
| # | 门槛 | 能否绕过 | 严重度 |
|---|---|---|---|
| 1 | CSRF 双提交:所有写请求(含登录)强制要求 Cookie + Header 同时携带 | 可绕,但依赖小程序 cookie 行为,需先做 PoC | 🔴 决定成败 |
| 2 | 服务器域名:体验版强制校验 HTTPS + ICP 备案域名 | 真机"打开调试"可临时绕过 | 🟡 影响体验 |
| 3 | 功能范围:现有 20 个主页面是重表格 + 弹窗形态 | 必须裁剪,不能照搬 | 🟡 影响工期 |
关于你担心的"教育类可能无法上线"——在"仅做体验版"这个目标下,这个担心基本不成立。体验版不走审核流程,类目资质与 ICP 备案只影响正式上架。详见第三节。
一、后端兼容性实测(已本地跑通)
我起了本地服务(:3002),用 curl 模拟小程序的请求特征(不发 Origin、纯 Header 认证)逐项验证:
| 能力 | 结论 | 依据 |
|---|---|---|
| CORS | ✅ 零改动 | app.js:76 对无 Origin 请求直接放行(注释明确写了"移动端等非浏览器客户端")。小程序 wx.request 不发 Origin |
| Bearer 认证 | ✅ 零改动 | auth.middleware.js:66 优先读 Authorization: Bearer,Cookie 只是备选。实测纯 Bearer 零 Cookie 成功拉到数据 |
| 登录返回值 | ✅ 零改动 | 响应体直出 token / refreshToken / csrfToken,不需要读 Cookie 就能拿全所有凭据 |
| Token 续期 | ✅ 零改动 | auth.routes.js:181 支持 req.body.refresh_token;小程序发 camelCase 的 refreshToken,命名中间件自动转 snake_case。实测换票成功 |
| 命名风格 | ✅ 零改动 | convertRequestNaming / convertResponseNaming 全局生效,小程序端与 Vue 端一样全程写 camelCase |
| CSRF 校验 | ⚠️ 唯一卡点 | 见下节 |
实测记录
# 步骤1:GET /api/auth/csrf-token
# → 响应体直接返回 {"csrfToken":"8d8926..."},同时 Set-Cookie: XSRF-TOKEN=8d8926...; SameSite=Strict
# 测试A:POST /api/auth/login,只带 X-CSRF-Token 头,不带 Cookie
{"success":false,"message":"CSRF验证失败,请刷新页面后重试"} # ❌ 403
# 测试B:POST /api/auth/login,Header + Cookie 都带
{"success":true,"data":{"user":{...},"token":"eyJ...","refreshToken":"eyJ..."}} # ✅
# 测试C:纯 Bearer 读数据,零 Cookie
GET /api/query/semester → ✅ 216 个班级,字段已自动转 camelCase
GET /api/teachers → ✅ 正常分页返回
GET /api/dashboard/stats → ⚠️ {"success":false,"message":"请选择学期"}(需带 semester 参数,非阻塞)
# 测试D:POST /api/auth/refresh,body 传 camelCase refreshToken
{"success":true,"data":{"token":"eyJ..."}} # ✅ 命名中间件自动转换生效结论:读操作(GET)完全无障碍;写操作(含登录)卡在 CSRF。
二、CSRF 卡点分析(决定成败的关键)
问题本质
validateCsrf(app.js:137)是全局中间件,对所有 POST/PUT/DELETE 强制要求:
- Header
X-CSRF-Token与 CookieXSRF-TOKEN同时存在且值相等(Double Submit) - 该 token 的 HMAC 签名有效
/api/auth/login 也在其管辖范围内 —— 也就是说,小程序若无法携带 Cookie,连登录都进不去,整个方案卡死在第一步。
小程序侧的不确定性
微信 wx.request 的 Cookie 行为在官方文档中没有明确承诺,社区反馈存在矛盾:
- 一说微信有全局 Cookie 容器,会自动存
Set-Cookie并在同域请求自动回带(多数项目按此实践) - 一说小程序"阉割"了自动 Cookie,必须手动从
res.header['Set-Cookie']提取再手动注入 - 还有反馈称手动设置 header 的
Cookie字段会被客户端覆盖或忽略,且 iOS / Android / 开发者工具三端行为不一致
叠加后端 Cookie 带了 SameSite=Strict,微信客户端如何处理该属性也无保证。
这一条必须用 15 分钟的 PoC 先验证,不要在没验证前动手写业务代码。 PoC 内容:小程序里
GET /api/auth/csrf-token→ 拿响应体的 csrfToken →POST /api/auth/login同时塞 Header 和 Cookie → 看能否登录成功。需在开发者工具 + iOS 真机 + Android 真机三端各跑一次。
三种应对方案
| 方案 | 做法 | 改动范围 | 评价 |
|---|---|---|---|
| A. 直连(PoC 通过时) | 小程序封装 request,自动维护 csrfToken,写请求时同时注入 Header 与 Cookie | 零改动,纯新增小程序目录 | ⭐ 首选。最轻,符合约束 |
| B. 纯只读(PoC 失败的兜底) | 小程序只做查询展示,写操作全部不做;登录改用……问题是登录本身就是 POST | 零改动,但登录也是 POST,仍卡 | ❌ 不成立,除非配合 C |
| C. Nginx 注入(最稳) | 反向代理开一个 /mp-api/ 路径,在 Nginx 层根据 X-CSRF-Token 头自动补 Cookie: XSRF-TOKEN=同值 | 不改代码,只改运维配置 | ⭐ 强烈推荐作为保险。3 行 proxy_set_header 搞定 |
| D. BFF 中间层 | 新起一个 Node 小服务持 cookie jar 转发 | 不改现有代码,但多一个进程 | 🔧 最重,非必要不上 |
建议路线:先做 A 的 PoC,失败则上 C。 C 方案本质上只是在代理层补一个 Header,不触碰任何业务逻辑,完全符合"不改动现有项目"的约束。
三、微信平台侧门槛
3.1 服务器域名(真正的拦路虎)
体验版运行在生产级安全沙箱中,强制校验:
- 域名已在小程序后台「开发管理 → 服务器域名」配置(不含协议、端口、路径)
- 域名已完成 ICP 备案
- 有效 HTTPS 证书(非自签、含完整信任链)、TLS 1.2+
- ⚠️ 不支持非 443 端口的特殊端口要谨慎,目前部署是
3000:3000,必须走 Nginx 反代到 443
唯一的免费出路:真机扫码打开体验版后,点右上角「···」→「打开调试」,可临时跳过域名校验。 代价是每个体验用户每次都要手动开调试,且这个开关会随小程序重启失效——内部小范围演示够用,给领导演示会很尴尬。
如果学校/单位已有备案域名(看部署脚本走的是 1Panel /opt/www/sites/kec/,很可能已经有),那这一条直接消失,配个二级域名即可。
3.2 类目与审核(你担心的点,实际影响很小)
| 事项 | 对体验版的影响 |
|---|---|
| 教育类目资质(办学许可证等) | 无影响。体验版不提交审核 |
| 小程序 ICP 备案 | 无影响。仅影响正式上架(未备案上架会限 50 用户/天、搜不到、90 天内不备案则下架) |
| 服务类目选择 | 注册时要选,但本项目是校内教务管理工具,不是 C 端在线教育,可选「工具 → 效率」或「IT科技 → 软件服务」,完全避开教育类资质要求 |
所以"因涉及教育类可能无法上线"这个前提,其实是可以被绕开的 —— 只要产品定位讲清楚是内部管理工具而非面向学生招生/授课,正式上线也未必没戏。当然,先做体验版是稳妥的。
3.3 体验成员数量上限
| 主体类型 | 项目成员 | 体验成员 |
|---|---|---|
| 个人 | 15 | 15 |
| 企业/组织(未认证/已认证/已发布) | 20 | 30 / 60 / 90 |
校内教务小范围使用,个人主体的 15 人通常够;如果要给全院老师用,需要企业主体。
3.4 其他平台限制(开发时要注意)
wx.request并发上限 5,第 6 个请求静默挂起 → 首页别一口气打 8 个接口- 后端限流 120 次/分钟/IP(
app.js:114),生产环境生效,多人同时用要留意 - 主包 ≤ 2MB,总包 ≤ 20MB —— 对纯查询类小程序绰绰有余
timeout只接受 1000–60000ms
四、工作量评估与功能裁剪建议
现状规模
- 45 个
.vue文件(约 20 个主页面 + 25 个子组件/弹窗) - 19 个通用组件、17 个 API 模块、3 个 store
- Element Plus 重表格 + 多层弹窗 + 排课算法交互(
TeachingArrange一个页面就带 10 个子组件)
照搬是错的
管理后台的「大宽表 + 多列筛选 + 批量操作 + 模态弹窗」范式在 375px 宽的手机上基本不可用。建议按「小程序做查询、Web 做管理」分工:
| 模块 | 是否移植 | 理由 |
|---|---|---|
| 登录 / 改密 | ✅ 必做 | 入口 |
| Dashboard 概览 | ✅ 推荐 | 卡片式,天然适配手机 |
| 学期开课查询 | ✅ 推荐 | 高频只读,移动端价值最大 |
| 教材使用查询 | ✅ 推荐 | 同上 |
| 教师课时查询/统计 | ✅ 推荐 | 老师自查周课时,移动端刚需 |
| 班级/课程/专业 列表查询 | 🟡 可选 | 只读列表 + 搜索 |
| 教学安排(排课) | ❌ 不建议 | 10 个子组件、算法交互、长时任务,手机上做不了也不该做 |
| 导入 / 导出 | ❌ 不建议 | Excel 上传下载在小程序上体验很差 |
| 系统设置 / 用户管理 / 审计日志 | ❌ 不建议 | 低频管理操作,留在 Web 端 |
推荐 MVP
6 个页面、纯只读 + 登录:登录 → 首页概览 → 开课查询 → 教材查询 → 教师课时 → 我的信息。
这样做还有一个额外好处:除登录外全是 GET,CSRF 卡点只剩登录一处,风险面收敛到最小。
技术选型建议
| 选项 | 评价 |
|---|---|
| 原生小程序 + TDesign MiniProgram | ⭐ 推荐。包体最小、启动最快、无构建链路负担,TDesign 组件齐全且是腾讯官方出品 |
| uni-app / Taro | 生态熟悉可用,但为 6 个页面引入完整构建链不划算 |
目录建议放在项目根下新建 miniprogram/,与 client/ server/ 平级,不侵入现有任何目录。
五、风险清单
| 风险 | 等级 | 应对 |
|---|---|---|
| 小程序无法携带 Cookie → 登录失败 | 🔴 高 | 先做 PoC;失败则用 Nginx 注入 Cookie(方案 C) |
| 无备案域名 → 体验版必须开调试才能用 | 🟡 中 | 确认单位是否已有备案域名;否则接受"开调试"的临时方案 |
后端 SameSite=Strict 在微信客户端行为未知 | 🟡 中 | PoC 时一并验证 |
| 15 分钟 access token 过期 → 频繁续期 | 🟢 低 | 封装 request 时做 401 自动 refresh 重试(Web 端已有同款逻辑可参考) |
强制改密(MUST_CHANGE_PASSWORD 403) | 🟢 低 | 小程序端识别该 code,引导跳改密页 |
| 生产限流 120/min | 🟢 低 | 首页接口合并、加缓存 |
| 导出 Excel 在小程序端 | 🟢 低 | MVP 不做;后续可用下载票据 + wx.downloadFile + wx.openDocument |
六、建议的下一步
第 1 步(0.5 天):PoC 验证——只写 1 个页面,验证 3 件事:
- 小程序能否完成登录(Cookie 能否带上)
- 纯 Bearer 能否拉到
/api/query/semester数据 - 401 后 refresh 能否自动续期
PoC 通过 → 后续开发基本无技术风险。PoC 不通过 → 加一层 Nginx 配置,再通。
第 2 步(2-3 天):MVP 6 个页面——原生小程序 + TDesign,只读为主。
第 3 步:真机验证 + 体验版发布——需要你提供:小程序 AppID、后端公网 HTTPS 地址。
附:需要你确认的信息
- 是否已有已备案的 HTTPS 域名指向后端?(决定体验版是否必须开调试模式)
- 小程序账号的主体类型?(个人 15 人 / 企业最多 90 人体验成员)
- MVP 功能范围是否认可上面的 6 页方案?有没有必须加的模块?
- 是否接受在 Nginx 层加配置(不改代码)作为 CSRF 的兜底方案?