微信推送消息配置完整指南
📋 文档概述
本文档将详细介绍如何在 Next.js 项目中集成微信公众号消息推送功能,包括服务器验证、消息接收处理、用户管理等完整流程。
🎯 功能特性
- ✅ 服务器验证 - 微信服务器URL验证
- ✅ 消息处理 - 文本、事件、扫码等消息类型
- ✅ 用户管理 - 关注/取消关注事件处理
- ✅ 数据存储 - 用户信息自动保存到数据库
- ✅ 智能回复 - 基于消息内容的自动回复
- ✅ 错误处理 - 完善的异常处理机制
🔧 前置条件
1. 环境要求
- Node.js 18+
- PostgreSQL 数据库
- 公网可访问的服务器(或内网穿透工具)
- 已认证的微信公众号
2. 项目依赖
{
"next": "^15.0.0",
"@prisma/client": "latest",
"crypto": "built-in"
}
🚀 配置步骤
步骤 1: 微信公众号基础配置
1.1 获取 AppID 和 AppSecret
- 登录 微信公众平台
- 进入 开发 → 基本配置
- 记录 AppID 和 AppSecret
- 记录 Token(用于服务器验证)
1.2 配置服务器地址
- 在 开发 → 基本配置 → 服务器配置 中
- 填入服务器URL:
https://yourdomain.com/api/wechat/message - 填入Token(与环境变量中保持一致)
- 选择 明文模式(推荐)
- 点击 提交 进行验证
步骤 2: 环境变量配置
在项目根目录创建 .env 文件:
# 微信公众号配置
WECHAT_APP_ID="wxabcdefg1234567"
WECHAT_APP_SECRET="1234567890abcdefghijklmnopqrstuv"
WECHAT_TOKEN="your_custom_token_here"
# 前端配置
NEXT_PUBLIC_WECHAT_APP_ID="wxabcdefg1234567"
# 数据库配置
DATABASE_URL="postgresql://username:password@localhost:5432/database_name"
# 认证配置
AUTH_SECRET="your-secret-key-here"
NEXTAUTH_URL="https://yourdomain.com"
步骤 3: 数据库模型配置
3.1 Prisma Schema 配置
// prisma/schema.prisma
model WechatUser {
id String @id @default(cuid())
openid String @unique
unionid String?
nickname String?
headimgurl String?
sex Int @default(0)
language String @default("zh_CN")
city String?
province String?
country String?
isSubscribed Boolean @default(true)
subscribeTime DateTime @default(now())
unsubscribeTime DateTime?
subscribeScene String?
qrScene Int?
qrSceneStr String?
remark String?
groupid Int @default(0)
tagidList Json @default("[]")
lastActiveAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("wechat_users")
}
3.2 数据库迁移
# 生成 Prisma 客户端
npx prisma generate
# 推送模式到数据库
npx prisma db push
# 或使用迁移(生产环境推荐)
npx prisma migrate dev --name add_wechat_user
💻 代码实现
1. 环境变量配置文件
// src/env.js
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
server: {
WECHAT_APP_ID: z.string().optional(),
WECHAT_APP_SECRET: z.string().optional(),
WECHAT_TOKEN: z.string().optional(),
DATABASE_URL: z.string().url(),
},
client: {
NEXT_PUBLIC_WECHAT_APP_ID: z.string().optional(),
},
runtimeEnv: {
WECHAT_APP_ID: process.env.WECHAT_APP_ID,
WECHAT_APP_SECRET: process.env.WECHAT_APP_SECRET,
WECHAT_TOKEN: process.env.WECHAT_TOKEN,
NEXT_PUBLIC_WECHAT_APP_ID: process.env.NEXT_PUBLIC_WECHAT_APP_ID,
DATABASE_URL: process.env.DATABASE_URL,
},
});
2. 微信用户服务
// src/server/services/wechat-user.ts
import { db } from "@/server/db";
export interface WechatUserInfo {
openid: string;
unionid?: string;
nickname?: string;
headimgurl?: string;
sex?: number;
city?: string;
province?: string;
country?: string;
}
export interface SubscribeEventInfo {
openid: string;
eventKey?: string;
ticket?: string;
}
export class WechatUserService {
/**
* 处理用户关注事件
*/
static async handleSubscribeEvent(eventInfo: SubscribeEventInfo): Promise<void> {
try {
console.log('处理用户关注事件:', eventInfo);
const existingUser = await db.wechatUser.findUnique({
where: { openid: eventInfo.openid }
});
if (existingUser) {
// 用户重新关注,更新状态
await db.wechatUser.update({
where: { openid: eventInfo.openid },
data: {
isSubscribed: true,
subscribeTime: new Date(),
unsubscribeTime: null,
subscribeScene: eventInfo.eventKey ? `qr_scene_${eventInfo.eventKey}` : 'ADD_SCENE_OTHERS',
qrScene: eventInfo.eventKey ? parseInt(eventInfo.eventKey) : null,
qrSceneStr: eventInfo.eventKey || '',
lastActiveAt: new Date(),
updatedAt: new Date()
}
});
} else {
// 新用户关注,创建记录
await db.wechatUser.create({
data: {
openid: eventInfo.openid,
isSubscribed: true,
subscribeTime: new Date(),
subscribeScene: eventInfo.eventKey ? `qr_scene_${eventInfo.eventKey}` : 'ADD_SCENE_OTHERS',
qrScene: eventInfo.eventKey ? parseInt(eventInfo.eventKey) : null,
qrSceneStr: eventInfo.eventKey || '',
lastActiveAt: new Date()
}
});
}
// 异步更新用户详细信息
setTimeout(() => {
WechatUserService.updateUserInfo(eventInfo.openid).catch(error => {
console.error('异步更新用户信息失败:', error);
});
}, 1000);
} catch (error) {
console.error('处理用户关注事件失败:', error);
throw error;
}
}
/**
* 处理用户取消关注事件
*/
static async handleUnsubscribeEvent(openid: string): Promise<void> {
try {
await db.wechatUser.updateMany({
where: { openid },
data: {
isSubscribed: false,
unsubscribeTime: new Date(),
lastActiveAt: new Date()
}
});
} catch (error) {
console.error('处理用户取消关注事件失败:', error);
throw error;
}
}
/**
* 更新用户详细信息
*/
static async updateUserInfo(openid: string): Promise<void> {
try {
const baseUrl = process.env.NEXTAUTH_URL || 'http://localhost:3000';
const response = await fetch(
`${baseUrl}/api/wechat/user-info?openid=${openid}&app_type=official_account`
);
if (!response.ok) {
throw new Error(`获取用户信息失败: ${response.status}`);
}
const result = await response.json();
if (!result.success || !result.data?.user_info) {
console.warn(`获取用户详细信息失败: ${result.error || '未知错误'}`);
return;
}
const userInfo = result.data.user_info as WechatUserInfo;
await db.wechatUser.update({
where: { openid },
data: {
unionid: userInfo.unionid || null,
nickname: userInfo.nickname || null,
headimgurl: userInfo.headimgurl || null,
sex: userInfo.sex || 0,
city: userInfo.city || null,
province: userInfo.province || null,
country: userInfo.country || null,
lastActiveAt: new Date(),
updatedAt: new Date()
}
});
console.log(`用户信息更新成功: ${userInfo.nickname} (${openid})`);
} catch (error) {
console.error('更新用户信息失败:', error);
}
}
}
3. 消息推送API接口
// src/app/api/wechat/message/route.ts
import { type NextRequest, NextResponse } from "next/server";
import { env } from "@/env";
import { WechatUserService } from '@/server/services/wechat-user';
import crypto from "crypto";
// 微信消息类型定义
interface WeChatMessage {
ToUserName: string;
FromUserName: string;
CreateTime: number;
MsgType: string;
MsgId?: string;
Content?: string;
Event?: string;
EventKey?: string;
[key: string]: string | number | undefined;
}
// 验证微信服务器签名
function verifySignature(params: {
signature: string;
timestamp: string;
nonce: string;
}, token: string): boolean {
const { signature, timestamp, nonce } = params;
const tmpArr = [token, timestamp, nonce].sort();
const tmpStr = tmpArr.join("");
const hash = crypto.createHash("sha1").update(tmpStr).digest("hex");
return hash === signature;
}
// 处理文本消息
function handleTextMessage(message: WeChatMessage): string {
const content = message.Content ?? "";
let replyContent = "";
// 智能回复逻辑
if (content.includes("帮助") || content.includes("help")) {
replyContent = `🤖 智能助手为您服务
可用功能:
• 发送"阿姨" - 查看阿姨信息
• 发送"雇主" - 查看雇主需求
• 发送"招聘" - 查看最新招聘
• 发送"联系" - 获取联系方式
💡 您也可以直接描述需求,我会为您提供相关信息。`;
} else if (content.includes("阿姨")) {
replyContent = `👩🦳 阿姨服务信息
我们有专业的家政阿姨:
• 月嫂 - 专业护理新生儿和产妇
• 育儿嫂 - 科学育儿指导
• 保姆 - 家务料理和老人照护
• 钟点工 - 灵活时间服务
如需了解详情,请发送具体服务类型。`;
} else if (content.includes("雇主") || content.includes("招聘")) {
replyContent = `👔 雇主招聘信息
当前热门需求:
• 住家保姆 - 月薪8000-12000元
• 育儿嫂 - 月薪10000-15000元
• 月嫂 - 月薪15000-25000元
• 钟点工 - 时薪50-80元
📞 如需发布招聘或应聘,请联系客服。`;
} else if (content.includes("联系") || content.includes("客服")) {
replyContent = `📞 联系方式
客服热线:400-123-4567
服务时间:09:00-18:00
微信客服:ayibang_service
在线咨询:www.ayibang.com
💬 您也可以直接在此对话,我们会及时回复。`;
} else {
replyContent = `收到您的消息:${content}
感谢您的关注!如需帮助请发送"帮助"查看可用功能。
当前时间:${new Date().toLocaleString('zh-CN')}`;
}
return `<xml>
<ToUserName><![CDATA[${message.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${message.ToUserName}]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${replyContent}]]></Content>
</xml>`;
}
// 处理关注事件
async function handleSubscribeEvent(message: WeChatMessage): Promise<string> {
const fromUserName = message.FromUserName ?? "";
const eventKey = message.EventKey ?? "";
console.log('用户关注事件:', { fromUserName, eventKey });
// 异步处理数据库操作,不阻塞消息回复
setTimeout(() => {
void (async () => {
try {
await WechatUserService.handleSubscribeEvent({
openid: fromUserName,
eventKey: eventKey || undefined
});
console.log(`用户 ${fromUserName} 关注事件处理成功`);
} catch (error) {
console.error('处理关注事件失败:', error);
}
})();
}, 100);
const welcomeMessage = `🎉 欢迎关注阿姨帮!
感谢您的关注,我们将为您提供优质的家政服务信息。
您可以:
• 发送"帮助" - 查看功能介绍
• 发送"阿姨" - 了解阿姨信息
• 发送"雇主" - 了解雇主需求
• 发送"招聘" - 查看最新职位
🔥 优质阿姨推荐,专业服务保障
如有任何问题,请随时联系我们!`;
return `<xml>
<ToUserName><![CDATA[${message.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${message.ToUserName}]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${welcomeMessage}]]></Content>
</xml>`;
}
// 处理取消关注事件
async function handleUnsubscribeEvent(message: WeChatMessage): Promise<string> {
const fromUserName = message.FromUserName ?? "";
console.log('用户取消关注事件:', { fromUserName });
setTimeout(() => {
void (async () => {
try {
await WechatUserService.handleUnsubscribeEvent(fromUserName);
console.log(`用户 ${fromUserName} 取消关注事件处理成功`);
} catch (error) {
console.error('处理取消关注事件失败:', error);
}
})();
}, 100);
// 取消关注不需要回复
return "";
}
// 处理事件
async function handleEvent(message: WeChatMessage): Promise<string> {
const event = message.Event ?? "";
switch (event) {
case "subscribe":
return handleSubscribeEvent(message);
case "unsubscribe":
return handleUnsubscribeEvent(message);
case "SCAN":
// 处理扫码事件
return `<xml>
<ToUserName><![CDATA[${message.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${message.ToUserName}]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[扫码成功!欢迎使用阿姨帮服务。]]></Content>
</xml>`;
default:
return `<xml>
<ToUserName><![CDATA[${message.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${message.ToUserName}]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[收到事件:${event}]]></Content>
</xml>`;
}
}
// 处理消息
async function handleMessage(message: WeChatMessage): Promise<string> {
console.log("收到微信消息:", message);
switch (message.MsgType) {
case "text":
return handleTextMessage(message);
case "event":
return await handleEvent(message);
default:
return `<xml>
<ToUserName><![CDATA[${message.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${message.ToUserName}]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[暂不支持此类型消息,请发送文字消息。]]></Content>
</xml>`;
}
}
// 解析XML消息
function parseXMLMessage(xmlString: string): WeChatMessage {
const message: WeChatMessage = {} as WeChatMessage;
const patterns = {
ToUserName: /<ToUserName><!\[CDATA\[(.*?)\]\]><\/ToUserName>/,
FromUserName: /<FromUserName><!\[CDATA\[(.*?)\]\]><\/FromUserName>/,
CreateTime: /<CreateTime>(.*?)<\/CreateTime>/,
MsgType: /<MsgType><!\[CDATA\[(.*?)\]\]><\/MsgType>/,
Content: /<Content><!\[CDATA\[(.*?)\]\]><\/Content>/,
Event: /<Event><!\[CDATA\[(.*?)\]\]><\/Event>/,
EventKey: /<EventKey><!\[CDATA\[(.*?)\]\]><\/EventKey>/,
MsgId: /<MsgId>(.*?)<\/MsgId>/
};
Object.entries(patterns).forEach(([key, pattern]) => {
const match = pattern.exec(xmlString);
if (match) {
if (key === 'CreateTime') {
message[key] = parseInt(match[1]!);
} else {
message[key] = match[1]!;
}
}
});
return message;
}
// GET请求 - 微信服务器验证
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const signature = searchParams.get("signature") ?? "";
const timestamp = searchParams.get("timestamp") ?? "";
const nonce = searchParams.get("nonce") ?? "";
const echostr = searchParams.get("echostr") ?? "";
console.log("微信服务器验证请求:", {
signature,
timestamp,
nonce,
echostr,
});
// 验证签名
const token = env.WECHAT_TOKEN ?? "your-wechat-token";
const isValid = verifySignature({ signature, timestamp, nonce }, token);
if (isValid) {
console.log("微信服务器验证成功");
return new NextResponse(echostr, { status: 200 });
} else {
console.log("微信服务器验证失败");
return new NextResponse("验证失败", { status: 403 });
}
} catch (error) {
console.error("微信服务器验证错误:", error);
return new NextResponse("服务器错误", { status: 500 });
}
}
// POST请求 - 接收微信消息推送
export async function POST(request: NextRequest) {
try {
const xmlData = await request.text();
console.log("收到微信推送消息:", xmlData);
// 解析XML消息
const message = parseXMLMessage(xmlData);
console.log("解析后的消息:", message);
// 处理消息并生成回复
const reply = await handleMessage(message);
if (reply) {
console.log("回复消息:", reply);
return new NextResponse(reply, {
status: 200,
headers: {
"Content-Type": "application/xml; charset=utf-8",
},
});
} else {
// 不需要回复的消息(如取消关注)
return new NextResponse("success", { status: 200 });
}
} catch (error) {
console.error("处理微信消息推送错误:", error);
return new NextResponse("success", { status: 200 });
}
}
🧪 测试验证
1. 服务器验证测试
# 测试GET请求(服务器验证)
curl -X GET "https://yourdomain.com/api/wechat/message?signature=test×tamp=1234567890&nonce=abc123&echostr=hello"
2. 消息推送测试
# 测试POST请求(消息推送)
curl -X POST "https://yourdomain.com/api/wechat/message" \
-H "Content-Type: application/xml" \
-d "<xml>
<ToUserName><![CDATA[gh_test123456]]></ToUserName>
<FromUserName><![CDATA[o_test123456]]></FromUserName>
<CreateTime>1234567890</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[测试消息]]></Content>
<MsgId>123456789</MsgId>
</xml>"
3. 功能测试页面
创建测试页面 /wechat-message-test:
// src/app/wechat-message-test/page.tsx
"use client";
import { useState } from "react";
export default function WeChatMessageTestPage() {
const [webhookUrl, setWebhookUrl] = useState("");
const [testResult, setTestResult] = useState("");
const generateWebhookUrl = () => {
const url = `${window.location.origin}/api/wechat/message`;
setWebhookUrl(url);
};
const testServerVerification = async () => {
try {
const params = new URLSearchParams({
signature: "test_signature",
timestamp: Date.now().toString(),
nonce: "test_nonce",
echostr: "test_echo"
});
const response = await fetch(`/api/wechat/message?${params}`);
const result = await response.text();
setTestResult(`服务器验证测试结果: ${response.status} - ${result}`);
} catch (error) {
setTestResult(`测试失败: ${error}`);
}
};
const testMessagePush = async () => {
try {
const xmlMessage = `<xml>
<ToUserName><![CDATA[gh_test123456]]></ToUserName>
<FromUserName><![CDATA[o_test123456]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[帮助]]></Content>
<MsgId>123456789</MsgId>
</xml>`;
const response = await fetch("/api/wechat/message", {
method: "POST",
headers: { "Content-Type": "application/xml" },
body: xmlMessage,
});
const result = await response.text();
setTestResult(`消息推送测试结果: ${response.status} - ${result}`);
} catch (error) {
setTestResult(`测试失败: ${error}`);
}
};
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-6">微信消息推送测试</h1>
<div className="space-y-6">
<div className="bg-white p-6 rounded-lg shadow">
<h2 className="text-xl font-semibold mb-4">Webhook URL</h2>
<div className="flex gap-2">
<input
type="text"
value={webhookUrl}
readOnly
placeholder="点击生成按钮获取URL"
className="flex-1 px-3 py-2 border rounded"
/>
<button
onClick={generateWebhookUrl}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
生成URL
</button>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<h2 className="text-xl font-semibold mb-4">功能测试</h2>
<div className="space-y-4">
<button
onClick={testServerVerification}
className="w-full px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
>
测试服务器验证
</button>
<button
onClick={testMessagePush}
className="w-full px-4 py-2 bg-purple-500 text-white rounded hover:bg-purple-600"
>
测试消息推送
</button>
</div>
</div>
{testResult && (
<div className="bg-gray-100 p-4 rounded-lg">
<h3 className="font-semibold mb-2">测试结果:</h3>
<pre className="text-sm">{testResult}</pre>
</div>
)}
</div>
</div>
);
}
🔍 故障排除
常见错误及解决方案
1. 服务器验证失败
错误现象: 微信公众平台显示"Token验证失败"
可能原因:
- Token不匹配
- 签名算法错误
- 服务器不可访问
解决方案:
// 检查Token配置
console.log("环境变量Token:", process.env.WECHAT_TOKEN);
// 检查签名算法
function debugSignature(timestamp: string, nonce: string, token: string) {
const tmpArr = [token, timestamp, nonce].sort();
console.log("排序后数组:", tmpArr);
const tmpStr = tmpArr.join("");
console.log("拼接字符串:", tmpStr);
const hash = crypto.createHash("sha1").update(tmpStr).digest("hex");
console.log("生成签名:", hash);
return hash;
}
2. 消息无响应
错误现象: 用户发送消息后无回复
可能原因:
- XML解析错误
- 消息处理异常
- 响应格式错误
解决方案:
// 添加详细日志
console.log("原始XML:", xmlData);
console.log("解析消息:", message);
console.log("生成回复:", reply);
// 验证XML格式
function validateXMLResponse(xml: string): boolean {
return xml.includes('<xml>') &&
xml.includes('</xml>') &&
xml.includes('<ToUserName>') &&
xml.includes('<FromUserName>');
}
3. 数据库连接错误
错误现象: 用户信息保存失败
解决方案:
// 添加错误处理
try {
await WechatUserService.handleSubscribeEvent(eventInfo);
} catch (error) {
console.error('数据库操作失败:', error);
// 继续返回欢迎消息,不影响用户体验
}
4. IP白名单问题
错误现象: 获取access_token失败
解决方案:
- 检查服务器公网IP
- 在微信公众平台添加IP到白名单
- 使用IP检查接口验证:
/api/wechat/check-ip
调试工具
1. 日志查看
# 查看服务器日志
tail -f logs/app.log
# 查看特定错误
grep "微信" logs/app.log
2. 接口测试
# 健康检查
curl https://yourdomain.com/api/health
# IP检查
curl https://yourdomain.com/api/wechat/check-ip
📈 性能优化
1. 异步处理
// 不阻塞主流程的异步处理
setTimeout(() => {
void (async () => {
await heavyOperation();
})();
}, 100);
2. 缓存机制
// 用户信息缓存
const userCache = new Map();
async function getCachedUserInfo(openid: string) {
if (userCache.has(openid)) {
return userCache.get(openid);
}
const userInfo = await fetchUserInfo(openid);
userCache.set(openid, userInfo);
// 设置过期时间
setTimeout(() => {
userCache.delete(openid);
}, 30 * 60 * 1000); // 30分钟
return userInfo;
}
3. 错误重试
async function retryOperation(operation: () => Promise<any>, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
🛡️ 安全考虑
1. 签名验证
// 严格验证微信签名
function strictSignatureVerification(params: any, token: string): boolean {
const { signature, timestamp, nonce } = params;
// 验证时间戳(避免重放攻击)
const now = Math.floor(Date.now() / 1000);
const timeGap = Math.abs(now - parseInt(timestamp));
if (timeGap > 300) { // 5分钟超时
return false;
}
// 验证签名
const tmpArr = [token, timestamp, nonce].sort();
const tmpStr = tmpArr.join("");
const hash = crypto.createHash("sha1").update(tmpStr).digest("hex");
return hash === signature;
}
2. 输入过滤
// 过滤恶意输入
function sanitizeInput(input: string): string {
return input
.replace(/<script[^>]*>.*?<\/script>/gi, '')
.replace(/<[^>]+>/g, '')
.trim()
.substring(0, 1000); // 限制长度
}
3. 频率限制
// 简单的频率限制
const rateLimiter = new Map();
function checkRateLimit(openid: string): boolean {
const key = `rate_limit_${openid}`;
const now = Date.now();
const lastRequest = rateLimiter.get(key) || 0;
if (now - lastRequest < 1000) { // 1秒内只能发送一条
return false;
}
rateLimiter.set(key, now);
return true;
}
🚀 部署指南
1. 环境变量检查
# 生产环境必要变量
export WECHAT_APP_ID="your_app_id"
export WECHAT_APP_SECRET="your_app_secret"
export WECHAT_TOKEN="your_token"
export DATABASE_URL="your_database_url"
export NEXTAUTH_URL="https://yourdomain.com"
2. 数据库迁移
# 生产环境迁移
npx prisma migrate deploy
# 验证数据库连接
npx prisma db pull
3. 服务启动
# 构建项目
npm run build
# 启动服务
npm run start
# 使用PM2管理
pm2 start npm --name "wechat-app" -- start
4. 监控配置
// 健康检查接口
export async function GET() {
try {
// 检查数据库连接
await db.$queryRaw`SELECT 1`;
// 检查微信配置
const hasWechatConfig = !!(process.env.WECHAT_APP_ID && process.env.WECHAT_APP_SECRET);
return NextResponse.json({
status: 'healthy',
timestamp: new Date().toISOString(),
database: 'connected',
wechat: hasWechatConfig ? 'configured' : 'missing_config'
});
} catch (error) {
return NextResponse.json({
status: 'unhealthy',
error: error.message
}, { status: 500 });
}
}
📚 最佳实践
1. 消息回复策略
- 5秒内必须响应
- 回复内容要有帮助性
- 支持关键词智能匹配
- 提供清晰的菜单指引
2. 用户体验优化
- 快速响应用户操作
- 提供有意义的错误提示
- 支持多轮对话
- 个性化推荐内容
3. 数据管理
- 定期清理过期数据
- 备份用户重要信息
- 监控系统性能指标
- 记录关键操作日志
4. 运维监控
- 设置告警机制
- 监控接口响应时间
- 统计用户活跃度
- 分析消息类型分布
📖 参考资料
💡 提示: 本文档基于实际项目经验编写,涵盖了从配置到部署的完整流程。如有疑问,请参考项目中的实际代码实现或联系技术支持。