/** * 小程序支付回调通知处理 * 微信支付成功后会调用此接口 */ import { NextResponse } from 'next/server' import crypto from 'crypto' const WECHAT_PAY_CONFIG = { appId: 'wxb8bbb2b10dec74aa', mchId: '1318592501', mchKey: 'wx3e31b068be59ddc131b068be59ddc2', } // 生成签名 function generateSign(params: Record, key: string): string { const sortedKeys = Object.keys(params).sort() const signString = sortedKeys .filter((k) => params[k] && k !== 'sign') .map((k) => `${k}=${params[k]}`) .join('&') const signWithKey = `${signString}&key=${key}` return crypto.createHash('md5').update(signWithKey, 'utf8').digest('hex').toUpperCase() } // 验证签名 function verifySign(params: Record, key: string): boolean { const receivedSign = params.sign if (!receivedSign) return false const data = { ...params } delete data.sign const calculatedSign = generateSign(data, key) return receivedSign === calculatedSign } // XML转对象 function xmlToDict(xml: string): Record { const result: Record = {} const regex = /<(\w+)><\/\1>/g let match while ((match = regex.exec(xml)) !== null) { result[match[1]] = match[2] } const simpleRegex = /<(\w+)>([^<]*)<\/\1>/g while ((match = simpleRegex.exec(xml)) !== null) { if (!result[match[1]]) { result[match[1]] = match[2] } } return result } // 成功响应 const SUCCESS_RESPONSE = ` ` // 失败响应 const FAIL_RESPONSE = ` ` /** * POST - 接收微信支付回调 */ export async function POST(request: Request) { try { const xmlData = await request.text() console.log('[PayNotify] 收到支付回调') const data = xmlToDict(xmlData) // 验证签名 if (!verifySign(data, WECHAT_PAY_CONFIG.mchKey)) { console.error('[PayNotify] 签名验证失败') return new Response(FAIL_RESPONSE, { headers: { 'Content-Type': 'application/xml' } }) } // 检查支付结果 if (data.return_code !== 'SUCCESS' || data.result_code !== 'SUCCESS') { console.log('[PayNotify] 支付未成功:', data.err_code, data.err_code_des) return new Response(SUCCESS_RESPONSE, { headers: { 'Content-Type': 'application/xml' } }) } const orderSn = data.out_trade_no const transactionId = data.transaction_id const totalFee = parseInt(data.total_fee || '0', 10) const openId = data.openid console.log('[PayNotify] 支付成功:', { orderSn, transactionId, totalFee, openId: openId?.slice(0, 10) + '...', }) // 解析附加数据 let attach: Record = {} if (data.attach) { try { attach = JSON.parse(data.attach) } catch (e) { // 忽略解析错误 } } const { productType, productId, userId } = attach // TODO: 这里应该更新数据库中的订单状态 // 1. 更新订单状态为已支付 // 2. 如果是章节购买,将章节添加到用户已购列表 // 3. 如果是全书购买,更新用户为全书用户 console.log('[PayNotify] 订单处理完成:', { orderSn, productType, productId, userId, }) // 返回成功响应给微信 return new Response(SUCCESS_RESPONSE, { headers: { 'Content-Type': 'application/xml' } }) } catch (error) { console.error('[PayNotify] 处理回调失败:', error) return new Response(FAIL_RESPONSE, { headers: { 'Content-Type': 'application/xml' } }) } }