#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 模拟微信「商家转账到零钱」结果通知回调,请求本地/远程回调接口, 用于验证:1)接口是否可达 2)wechat_callback_logs 表是否会写入一条记录。 说明:未使用真实签名与加密,服务端会验签失败并返回 500, 但仍会写入 wechat_callback_logs 一条 handler_result=fail 的记录。 运行前请确保 soul-api 已启动;运行后请查表 wechat_callback_logs 是否有新行。 """ import json import ssl import sys from datetime import datetime from urllib.request import Request, urlopen from urllib.error import URLError, HTTPError # 默认请求地址(可改环境或命令行) DEFAULT_URL = "http://localhost:8080/api/payment/wechat/transfer/notify" def main(): args = [a for a in sys.argv[1:] if a and not a.startswith("-")] insecure = "--insecure" in sys.argv or "-k" in sys.argv url = args[0] if args else DEFAULT_URL if insecure and url.startswith("https://"): print("已启用 --insecure,跳过 SSL 证书校验(仅用于本地/测试)") ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE else: ctx = None # 模拟微信回调的请求体结构(真实场景中 resource.ciphertext 为 AEAD_AES_256_GCM 加密,这里用占位) body = { "id": "test-notify-id-" + datetime.now().strftime("%Y%m%d%H%M%S"), "create_time": datetime.now().strftime("%Y-%m-%dT%H:%M:%S+08:00"), "resource_type": "encrypt-resource", "event_type": "MCHTRANSFER.BILL.FINISHED", "summary": "模拟转账结果通知", "resource": { "original_type": "mch_payment", "algorithm": "AEAD_AES_256_GCM", "ciphertext": "fake-base64-ciphertext-for-test", "nonce": "fake-nonce", "associated_data": "mch_payment", }, } body_bytes = json.dumps(body, ensure_ascii=False).encode("utf-8") headers = { "Content-Type": "application/json", "Wechatpay-Timestamp": str(int(datetime.now().timestamp())), "Wechatpay-Nonce": "test-nonce-" + datetime.now().strftime("%H%M%S"), "Wechatpay-Signature": "fake-signature-for-test", "Wechatpay-Serial": "fake-serial-for-test", } req = Request(url, data=body_bytes, headers=headers, method="POST") print(f"POST {url}") print(f"Body (摘要): event_type={body['event_type']}, resource_type={body['resource_type']}") print("-" * 50) try: with urlopen(req, timeout=10, context=ctx) as resp: print(f"HTTP 状态: {resp.status}") raw = resp.read().decode("utf-8", errors="replace") try: parsed = json.loads(raw) print("响应 JSON:", json.dumps(parsed, ensure_ascii=False, indent=2)) except Exception: print("响应 body:", raw[:500]) except HTTPError as e: print(f"HTTP 状态: {e.code}") raw = e.read().decode("utf-8", errors="replace") try: parsed = json.loads(raw) print("响应 JSON:", json.dumps(parsed, ensure_ascii=False, indent=2)) except Exception: print("响应 body:", raw[:500]) except URLError as e: print(f"请求失败: {e.reason}") sys.exit(1) print("-" * 50) print("请检查数据库表 wechat_callback_logs 是否有新记录(本次为模拟请求,预期会有一条 handler_result=fail 的记录)。") if __name__ == "__main__": main()