Files
qianyubtcandClaude Fable 5 f87ec65541 BinancePayTool v0.1.0:币安支付个人收款网关(Go 核心 + 四语言 SDK)
- Go 服务端:唯一金额/备注码/回填订单编号三路匹配、托管收银页、HMAC 回调七级重试、SQLite 单二进制
- SDK:Go / Java / PHP / Python,共享签名测试向量(docs/test_vectors.json)
- 跨语言 e2e(真实二进制 × Python SDK × mock 币安)、GitHub Actions CI、Dockerfile
- 协议文档 docs/protocol.md、调研与实测结论 docs/research.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 14:09:32 +08:00

74 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""最小商户示例(仅标准库)。
export BPG_BASE=http://127.0.0.1:8080 BPG_SECRET=你的API_AUTH_KEY
python3 app.py # 然后浏览器打开 http://127.0.0.1:9000/buy
"""
import json
import os
import sys
import time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "sdk", "python"))
from bpaygate import BPayGate, BPayGateError
BASE = os.environ.get("BPG_BASE", "http://127.0.0.1:8080")
SECRET = os.environ.get("BPG_SECRET", "")
PORT = int(os.environ.get("PORT", "9000"))
gw = BPayGate(BASE, SECRET)
class Shop(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith("/buy"):
mid = f"DEMO-{int(time.time())}"
try:
order = gw.create_order(
mid, "1", currency="USDT",
callback_url=f"http://127.0.0.1:{PORT}/notify",
return_url=f"http://127.0.0.1:{PORT}/done",
)
except BPayGateError as e:
self.send_response(500)
self.end_headers()
self.wfile.write(str(e).encode())
return
self.send_response(302)
self.send_header("Location", order["pay_url"])
self.end_headers()
elif self.path.startswith("/done"):
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.end_headers()
self.wfile.write("<h1>支付完成,感谢购买!</h1>".encode())
else:
self.send_response(404)
self.end_headers()
def do_POST(self):
if self.path != "/notify":
self.send_response(404)
self.end_headers()
return
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
try:
payload = BPayGate.verify_callback(self.headers, body, SECRET)
except BPayGateError as e:
print("回调验签失败:", e)
self.send_response(401)
self.end_headers()
return
# TODO: 按 merchant_order_id 幂等发货
print("收到回调:", payload["event"], payload["merchant_order_id"], payload.get("actual_amount"))
self.send_response(200)
self.end_headers()
def log_message(self, *a):
pass
if __name__ == "__main__":
print(f"商户示例: http://127.0.0.1:{PORT}/buy")
ThreadingHTTPServer(("127.0.0.1", PORT), Shop).serve_forever()