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>
This commit is contained in:
1 parent
e4275368ea
commit
f87ec65541
46 files changed
+4378
No files matched your search
@@ -0,0 +1,62 @@
|
||||
import com.bpaygate.sdk.BPayGateClient;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 最小商户示例(Java 8+,无 Web 框架)。
|
||||
* 编译运行后访问 http://127.0.0.1:9000/buy
|
||||
*/
|
||||
public class ExampleServer {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String base = System.getenv().getOrDefault("BPG_BASE", "http://127.0.0.1:8080");
|
||||
String secret = System.getenv().getOrDefault("BPG_SECRET", "");
|
||||
BPayGateClient gw = new BPayGateClient(base, secret);
|
||||
|
||||
HttpServer srv = HttpServer.create(new InetSocketAddress("127.0.0.1", 9000), 0);
|
||||
srv.createContext("/buy", ex -> {
|
||||
JsonObject order = gw.createOrder("DEMO-" + System.currentTimeMillis(), "USDT", "1",
|
||||
"http://127.0.0.1:9000/notify", "http://127.0.0.1:9000/done", 0);
|
||||
ex.getResponseHeaders().add("Location", order.get("pay_url").getAsString());
|
||||
ex.sendResponseHeaders(302, -1);
|
||||
ex.close();
|
||||
});
|
||||
srv.createContext("/notify", ex -> {
|
||||
String body = readAll(ex.getRequestBody());
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
ex.getRequestHeaders().forEach((k, v) -> headers.put(k, v.isEmpty() ? "" : v.get(0)));
|
||||
try {
|
||||
JsonObject payload = BPayGateClient.verifyCallback(headers, body, secret, 300000);
|
||||
// TODO: 按 merchant_order_id 幂等发货
|
||||
System.out.println("回调: " + payload.get("event") + " " + payload.get("merchant_order_id"));
|
||||
ex.sendResponseHeaders(200, -1);
|
||||
} catch (BPayGateClient.BPayGateException e) {
|
||||
ex.sendResponseHeaders(401, -1);
|
||||
}
|
||||
ex.close();
|
||||
});
|
||||
srv.createContext("/done", ex -> {
|
||||
byte[] b = "<h1>支付完成,感谢购买!</h1>".getBytes(StandardCharsets.UTF_8);
|
||||
ex.getResponseHeaders().add("Content-Type", "text/html; charset=utf-8");
|
||||
ex.sendResponseHeaders(200, b.length);
|
||||
try (OutputStream os = ex.getResponseBody()) { os.write(b); }
|
||||
});
|
||||
System.out.println("商户示例: http://127.0.0.1:9000/buy");
|
||||
srv.start();
|
||||
}
|
||||
|
||||
private static String readAll(InputStream is) throws java.io.IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[4096];
|
||||
int n;
|
||||
while ((n = is.read(buf)) > 0) bos.write(buf, 0, n);
|
||||
return new String(bos.toByteArray(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user