Files
AIclinicalresearch/backend/src/modules/iit-manager/docs/微信服务号接入指南.md
HaHafeng 2481b786d8 deploy: Complete 0126-27 deployment - database upgrade, services update, code recovery
Major Changes:
- Database: Install pg_bigm/pgvector plugins, create test database
- Python service: v1.0 -> v1.1, add pymupdf4llm/openpyxl/pypandoc
- Node.js backend: v1.3 -> v1.7, fix pino-pretty and ES Module imports
- Frontend: v1.2 -> v1.3, skip TypeScript check for deployment
- Code recovery: Restore empty files from local backup

Technical Fixes:
- Fix pino-pretty error in production (conditional loading)
- Fix ES Module import paths (add .js extensions)
- Fix OSSAdapter TypeScript errors
- Update Prisma Schema (63 models, 16 schemas)
- Update environment variables (DATABASE_URL, EXTRACTION_SERVICE_URL, OSS)
- Remove deprecated variables (REDIS_URL, DIFY_API_URL, DIFY_API_KEY)

Documentation:
- Create 0126 deployment folder with 8 documents
- Update database development standards v2.0
- Update SAE deployment status records

Deployment Status:
- PostgreSQL: ai_clinical_research_test with plugins
- Python: v1.1 @ 172.17.173.84:8000
- Backend: v1.7 @ 172.17.173.89:3001
- Frontend: v1.3 @ 172.17.173.90:80

Tested: All services running successfully on SAE
2026-01-27 08:13:27 +08:00

13 KiB
Raw Permalink Blame History

微信服务号接入指南(患者端)

版本: v1.0
创建日期: 2026-01-04
目标: 为患者端接入微信服务号,实现访视提醒和消息推送
预估工作量: 3天


📋 一、准备工作清单

1.1 微信服务号信息

已完成

  • 服务号名称:AI for 临床研究
  • AppIDwx062568ff49e4570c
  • AppSecretc0d19435d1a1e948939c16d767ec0faf
  • 认证状态: 已认证(企业认证)
  • 主体名称:北京壹证循科技有限公司

1.2 需要配置的参数

🔧 待配置

  1. Token3-32位字符串
  2. EncodingAESKey43位字符串
  3. 服务器URL(回调地址)

🔐 二、生成Token和EncodingAESKey

2.1 Token生成推荐使用随机字符串

# 方法1使用OpenSSL推荐
openssl rand -base64 24 | tr -d '/+=' | cut -c1-32

# 方法2使用Node.js
node -e "console.log(require('crypto').randomBytes(24).toString('base64').replace(/[\/\+=]/g, '').substring(0, 32))"

# 方法3在线生成器
# https://suijimimashengcheng.51240.com/

推荐Token(示例,请重新生成):

IitPatientWechat2026Jan04Abc

2.2 EncodingAESKey生成必须43位

# 方法1使用OpenSSL推荐
openssl rand -base64 43 | tr -d '/+=' | head -c 43

# 方法2使用Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64').replace(/[\/\+=]/g, '').substring(0, 43))"

# 方法3微信公众平台随机生成最简单
# 登录微信公众平台 → 基本配置 → 消息加密密钥 → 点击"随机生成"

推荐EncodingAESKey(示例,请重新生成):

abcdefghijklmnopqrstuvwxyz0123456789ABC

⚙️ 三、配置步骤(详细)

3.1 更新环境变量

编辑 backend/.env 文件,添加以下配置:

# ==========================================
# 微信服务号配置(患者端)
# ==========================================

# 微信服务号基础配置
WECHAT_MP_APP_ID=wx062568ff49e4570c
WECHAT_MP_APP_SECRET=c0d19435d1a1e948939c16d767ec0faf

# 微信服务号回调配置(消息加解密,安全模式)
WECHAT_MP_TOKEN=IitPatientWechat2026Jan04Abc
WECHAT_MP_ENCODING_AES_KEY=abcdefghijklmnopqrstuvwxyz0123456789ABC

# 微信小程序配置(可选,后续开发)
WECHAT_MINI_APP_ID=

⚠️ 注意

  1. Token和EncodingAESKey必须与微信公众平台配置的完全一致
  2. Token长度3-32位建议使用英文字母和数字
  3. EncodingAESKey长度必须43位,大小写敏感

3.2 配置微信公众平台

Step 1: 登录微信公众平台

访问:https://mp.weixin.qq.com/

使用管理员微信扫码登录(账号:zhi***ng

Step 2: 进入基本配置页面

左侧菜单 → 设置与开发 → 基本配置

Step 3: 配置服务器地址

找到 "服务器配置" 部分,点击 "修改配置"

填写以下信息:

配置项 说明
URL https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback 生产环境回调URL
Token IitPatientWechat2026Jan04Abc 与.env中的WECHAT_MP_TOKEN一致
EncodingAESKey abcdefghijklmnopqrstuvwxyz0123456789ABC 与.env中的WECHAT_MP_ENCODING_AES_KEY一致
消息加解密方式 安全模式(推荐) 选择"安全模式"
数据格式 XML 默认选择

本地开发环境使用natapp内网穿透

URL: https://devlocal.xunzhengyixue.com/api/v1/iit/patient-wechat/callback

Step 4: 点击"提交"并验证

微信会发送GET请求到您的服务器进行验证

GET https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback?signature=xxx&timestamp=xxx&nonce=xxx&echostr=xxx

验证成功标志

  • 页面显示"配置成功"
  • "服务器配置"状态为"已启用"

验证失败原因

  • Token不一致
  • 服务器无法访问(防火墙、未部署)
  • 代码逻辑错误(签名验证失败)

Step 5: 启用服务器配置

验证成功后,点击 "启用" 按钮。

⚠️ 注意:启用后,公众号的消息和事件会推送到您的服务器,不会显示在公众平台后台。


🧪 四、测试验证

4.1 测试URL验证手动测试

在配置微信公众平台时,点击"提交"按钮会自动触发URL验证。

查看后端日志:

# 本地开发
cd D:\MyCursor\AIclinicalresearch\backend
npm run dev

# 查看日志
# 应该看到类似以下日志:
# ✅ 微信服务号回调控制器初始化成功
# 📥 收到微信服务号 URL 验证请求
# ✅ URL 验证成功,返回 echostr

4.2 测试脚本1验证Token和AESKey配置

创建测试脚本 backend/src/modules/iit-manager/test-patient-wechat-config.ts

import dotenv from 'dotenv';
import crypto from 'crypto';

dotenv.config();

console.log('🔧 微信服务号配置检查\n');

// 1. 检查必需的环境变量
const requiredEnvs = [
  'WECHAT_MP_APP_ID',
  'WECHAT_MP_APP_SECRET',
  'WECHAT_MP_TOKEN',
  'WECHAT_MP_ENCODING_AES_KEY',
];

let hasError = false;

requiredEnvs.forEach((key) => {
  const value = process.env[key];
  if (!value) {
    console.error(`❌ 缺少环境变量: ${key}`);
    hasError = true;
  } else {
    console.log(`✅ ${key}: ${value.substring(0, 10)}... (长度: ${value.length})`);
  }
});

if (hasError) {
  console.error('\n❌ 配置不完整,请检查 .env 文件');
  process.exit(1);
}

// 2. 验证Token长度
const token = process.env.WECHAT_MP_TOKEN!;
if (token.length < 3 || token.length > 32) {
  console.error(`\n❌ Token长度不正确: ${token.length}应为3-32位`);
  hasError = true;
} else {
  console.log(`\n✅ Token长度正确: ${token.length}位`);
}

// 3. 验证EncodingAESKey长度
const aesKey = process.env.WECHAT_MP_ENCODING_AES_KEY!;
if (aesKey.length !== 43) {
  console.error(`❌ EncodingAESKey长度不正确: ${aesKey.length}必须43位`);
  hasError = true;
} else {
  console.log(`✅ EncodingAESKey长度正确: 43位`);
}

// 4. 测试签名生成
console.log('\n🔐 测试签名生成...');
const timestamp = Date.now().toString();
const nonce = Math.random().toString(36).substring(2);
const arr = [token, timestamp, nonce].sort();
const str = arr.join('');
const signature = crypto.createHash('sha1').update(str).digest('hex');

console.log(`生成的签名: ${signature}`);
console.log(`✅ 签名生成功能正常`);

// 5. 总结
if (hasError) {
  console.error('\n❌ 配置检查失败,请修复错误后重试');
  process.exit(1);
} else {
  console.log('\n✅ 配置检查通过!可以开始配置微信公众平台');
  console.log('\n📋 配置信息(用于微信公众平台):');
  console.log(`URL: https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback`);
  console.log(`Token: ${token}`);
  console.log(`EncodingAESKey: ${aesKey}`);
  console.log(`消息加解密方式: 安全模式(推荐)`);
}

运行测试

cd backend
npx tsx src/modules/iit-manager/test-patient-wechat-config.ts

4.3 测试脚本2模拟微信URL验证请求

创建测试脚本 backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts

import axios from 'axios';
import crypto from 'crypto';
import dotenv from 'dotenv';

dotenv.config();

const BASE_URL = 'http://localhost:3001';
const TOKEN = process.env.WECHAT_MP_TOKEN || '';

async function testUrlVerification() {
  console.log('🧪 测试微信服务号URL验证\n');

  // 1. 准备参数
  const timestamp = Date.now().toString();
  const nonce = Math.random().toString(36).substring(2, 12);
  const echostr = 'test_echo_' + Math.random().toString(36).substring(2);

  // 2. 生成签名
  const arr = [TOKEN, timestamp, nonce].sort();
  const str = arr.join('');
  const signature = crypto.createHash('sha1').update(str).digest('hex');

  console.log('📝 请求参数:');
  console.log(`  timestamp: ${timestamp}`);
  console.log(`  nonce: ${nonce}`);
  console.log(`  echostr: ${echostr}`);
  console.log(`  signature: ${signature}\n`);

  // 3. 发送GET请求
  try {
    const url = `${BASE_URL}/api/v1/iit/patient-wechat/callback`;
    const response = await axios.get(url, {
      params: {
        signature,
        timestamp,
        nonce,
        echostr,
      },
    });

    console.log('✅ URL验证成功');
    console.log(`返回内容: ${response.data}`);

    if (response.data === echostr) {
      console.log('✅ 返回的echostr正确');
    } else {
      console.error('❌ 返回的echostr不正确');
    }
  } catch (error: any) {
    console.error('❌ URL验证失败', error.message);
    if (error.response) {
      console.error('响应状态:', error.response.status);
      console.error('响应内容:', error.response.data);
    }
  }
}

testUrlVerification();

运行测试

# 先启动后端服务
npm run dev

# 新开一个终端,运行测试
npx tsx src/modules/iit-manager/test-patient-wechat-url-verify.ts

4.4 测试关注事件

  1. 用测试微信号关注公众号:AI for 临床研究
  2. 查看后端日志,应该看到:
📥 收到微信服务号回调消息
🔐 检测到加密消息,开始解密...
✅ 消息解密成功
📬 提取用户消息成功
🎯 处理事件消息: subscribe
👤 用户关注公众号: oXXXXXXXXXXXXXXXXX

4.5 测试文本消息

  1. 在公众号对话框发送文本消息:你好
  2. 查看后端日志,应该看到:
📥 收到微信服务号回调消息
🔐 检测到加密消息,开始解密...
✅ 消息解密成功
💬 处理文本消息: 你好
📝 文本消息已记录

🚀 五、部署上线

5.1 本地开发环境natapp内网穿透

1. 启动natapp

# Windows
cd D:\tools\natapp
natapp.exe -authtoken=YOUR_TOKEN -subdomain=devlocal

2. 验证映射

访问:https://devlocal.xunzhengyixue.com/api/v1/iit/health

应该返回:

{
  "status": "ok",
  "module": "iit-manager",
  "version": "1.1.0"
}

3. 配置微信公众平台

URL: https://devlocal.xunzhengyixue.com/api/v1/iit/patient-wechat/callback

5.2 生产环境SAE

1. 更新SAE环境变量

登录阿里云SAE控制台 → 应用管理 → 环境变量配置

添加以下环境变量:

WECHAT_MP_APP_ID=wx062568ff49e4570c
WECHAT_MP_APP_SECRET=c0d19435d1a1e948939c16d767ec0faf
WECHAT_MP_TOKEN=IitPatientWechat2026Jan04Abc
WECHAT_MP_ENCODING_AES_KEY=abcdefghijklmnopqrstuvwxyz0123456789ABC

2. 部署代码

cd backend
./deploy-to-sae.ps1

3. 验证部署

访问:https://iit.xunzhengyixue.com/api/v1/iit/health

4. 配置微信公众平台

URL: https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback

5. 配置IP白名单(重要):

登录微信公众平台 → 基本配置 → IP白名单

添加SAE应用的出口IP可以从SAE控制台查看


📋 六、常见问题排查

Q1: URL验证失败提示"Token验证失败"

原因

  • Token配置不一致大小写、多余空格
  • 签名计算错误

解决方法

  1. 检查 .env 文件中的 WECHAT_MP_TOKEN 是否与微信公众平台配置一致
  2. 运行配置检查脚本:npx tsx src/modules/iit-manager/test-patient-wechat-config.ts
  3. 查看后端日志,确认签名计算过程

Q2: URL验证失败提示"请求URL超时"

原因

  • 服务器未启动
  • 防火墙阻止
  • URL配置错误

解决方法

  1. 确认后端服务已启动:npm run dev
  2. 本地开发确认natapp已启动
  3. 生产环境确认SAE应用状态正常
  4. 使用浏览器直接访问健康检查接口测试连通性

Q3: 消息解密失败

原因

  • EncodingAESKey配置不一致
  • EncodingAESKey长度不正确必须43位

解决方法

  1. 检查 .env 文件中的 WECHAT_MP_ENCODING_AES_KEY 长度是否为43位
  2. 确认与微信公众平台配置完全一致(包括大小写)
  3. 重新生成EncodingAESKey并同步更新

Q4: 收不到用户消息

原因

  • 服务器配置未启用
  • 回调URL配置错误
  • 服务端代码异常

解决方法

  1. 登录微信公众平台,确认"服务器配置"状态为"已启用"
  2. 查看后端日志确认是否收到POST请求
  3. 检查是否有异常日志

📝 七、后续开发计划

Phase 1: 基础消息推送(当前)

  • 创建PatientWechatCallbackController
  • 创建PatientWechatService
  • 配置路由和环境变量
  • 测试URL验证
  • 测试消息接收

Phase 2: 患者绑定功能

  • 创建患者绑定数据表
  • 开发患者绑定H5页面
  • 实现手机号验证码功能
  • 实现患者身份验证逻辑

Phase 3: 模板消息推送

  • 申请模板消息权限
  • 设计访视提醒模板
  • 开发定时任务检测到期访视
  • 实现模板消息推送

Phase 4: 微信小程序

  • 注册微信小程序
  • 搭建小程序框架
  • 开发核心页面
  • 前后端联调

📞 联系方式

如有问题,请联系:


最后更新2026-01-04
文档版本v1.0