统一支付平台 Golang SDK 接入实战:支付宝、微信、PayPal 一次集成
做电商或会员体系的同学应该都有体会:支付通道一多,对接工作就变得琐碎——支付宝、微信、PayPal 各有一套接口、签名和回调逻辑,逐个适配既费时又容易出错。统一支付平台的官方 Golang SDK 就是来解决这个问题的:一套客户端配置,覆盖支付宝、微信支付、PayPal 等主流通道,接口设计简洁,且只依赖 Go 标准库。
项目地址:https://github.com/difyz9/payment-sdk-go
安装
和大多数 Go 库一样,一条命令完成引入:
go get github.com/difyz9/payment-sdk-go
快速上手
1. 初始化客户端
先准备好平台分配的 AppID、AppSecret,再指定 API 地址即可创建客户端实例:
package main
import (
"fmt"
"github.com/difyz9/payment-sdk-go"
)
func main() {
// 创建客户端配置
config := &paymentsdk.Config{
BaseURL: "https://api.example.com",
AppID: "your-app-id",
AppSecret: "your-app-secret",
}
// 创建客户端实例
client := paymentsdk.NewClient(config)
}
2. 创建支付订单
创建订单只需一个 PaymentRequest,核心字段是商品名称、金额和支付方式:
// 创建支付宝订单
req := &paymentsdk.PaymentRequest{
Subject: "VIP会员-月卡",
Amount: 0.01,
PayWay: paymentsdk.PayWayAlipay,
OrderType: "vip",
UserID: "user_12345",
Extra: `{"period":"30days"}`,
}
paymentData, err := client.CreatePayment(req)
if err != nil {
fmt.Printf("创建订单失败: %v\n", err)
return
}
fmt.Printf("支付链接: %s\n", paymentData.PayUrl)
fmt.Printf("订单号: %s\n", paymentData.OrderNo)
3. 查询订单状态
订单号是后续所有查询操作的入口:
// 查询单次
orderStatus, err := client.QueryOrder(orderNo)
if err != nil {
fmt.Printf("查询失败: %v\n", err)
return
}
if orderStatus.IsPaymentSuccess() {
fmt.Println("支付成功!")
}
4. 轮询订单状态
如果不想自己写循环,SDK 内置了轮询能力,可以设置查询间隔和最大次数:
// 自动轮询直到支付成功或超时
orderStatus, err := client.PollOrderStatus(orderNo, &paymentsdk.PollOptions{
Interval: 5 * time.Second, // 每5秒查询一次
MaxRetries: 12, // 最多查询12次
OnCheck: func(retry int, status *paymentsdk.OrderStatusData) {
fmt.Printf("[%d] 订单状态: %s\n", retry, paymentsdk.GetOrderStatusText(status.Status))
},
})
if err != nil {
fmt.Printf("轮询失败: %v\n", err)
return
}
fmt.Println("支付成功!")
核心 API 一览
客户端配置
type Config struct {
BaseURL string // API基础URL(必填)
AppID string // 应用ID(必填)
AppSecret string // 应用密钥(必填)
Timeout time.Duration // 请求超时时间(可选,默认30秒)
HTTPClient *http.Client // 自定义HTTP客户端(可选)
}
CreatePayment - 创建支付订单
func (c *Client) CreatePayment(req *PaymentRequest) (*PaymentData, error)
参数:
req.Subject(string, 必填) - 商品名称req.Amount(float64, 必填) - 支付金额(元)req.PayWay(string, 必填) - 支付方式:alipay/wechat/paypalreq.ReturnURL(string, 可选) - 支付成功返回地址(支付宝支付时使用)req.OrderType(string, 可选) - 订单类型req.UserID(string, 可选) - 用户IDreq.Extra(string, 可选) - 额外信息(JSON格式)req.Currency(string, 可选) - 货币代码(PayPal支付时使用,默认USD)req.BrandName(string, 可选) - 品牌名称(PayPal支付时显示)req.CancelURL(string, 可选) - 取消支付返回地址(PayPal支付时使用)
返回: PaymentData,包含支付链接和订单号。
QueryOrder - 查询订单状态
func (c *Client) QueryOrder(orderNo string) (*OrderStatusData, error)
传入订单号,返回订单的详细信息。
PollOrderStatus - 轮询查询订单状态
func (c *Client) PollOrderStatus(orderNo string, opts *PollOptions) (*OrderStatusData, error)
opts.Interval(time.Duration) - 查询间隔,默认5秒opts.MaxRetries(int) - 最大重试次数,默认12次opts.OnCheck(func) - 每次查询的回调函数opts.OnError(func) - 查询出错的回调函数
GetOrderList / CancelOrder / RefundOrder
订单管理相关的另外三个方法:
func (c *Client) GetOrderList(req *OrderListRequest) (*OrderListResponse, error)
func (c *Client) CancelOrder(orderNo, reason string) error
func (c *Client) RefundOrder(req *RefundRequest) (*RefundResponse, error)
各支付通道示例
支付宝支付
req := &paymentsdk.PaymentRequest{
Subject: "测试商品",
Amount: 0.01,
PayWay: paymentsdk.PayWayAlipay,
ReturnURL: "https://mystore.com/payment/success", // 支付成功后跳转的URL(可选)
OrderType: "product",
UserID: "user123",
}
paymentData, err := client.CreatePayment(req)
自定义返回地址(ReturnURL)说明:
支付宝支付完成后,用户会被重定向到指定的 ReturnURL;不设置则使用服务端配置的默认地址。
- 典型场景: 不同商品跳转到不同的成功页面、移动端和 PC 端使用不同的返回地址等
- 注意事项:
- 生产环境 ReturnURL 必须是公网可访问的 HTTPS 地址
- 支付宝会在 URL 后面追加支付结果参数
- 这是同步返回,仅用于页面跳转,订单状态以异步通知为准
- 建议在返回页面中调用
QueryOrder()再次验证订单状态
微信支付
req := &paymentsdk.PaymentRequest{
Subject: "测试商品",
Amount: 0.01,
PayWay: paymentsdk.PayWayWechat,
OrderType: "product",
UserID: "user123",
}
paymentData, err := client.CreatePayment(req)
// 返回的 PayUrl 是微信支付二维码链接
PayPal 支付
req := &paymentsdk.PaymentRequest{
Subject: "Test Product",
Amount: 1.00,
PayWay: paymentsdk.PayWayPaypal,
Currency: "USD",
BrandName: "My Store",
CancelURL: "https://example.com/cancel",
}
paymentData, err := client.CreatePayment(req)
获取订单列表
支持按用户、状态分页查询,方便后台管理:
listReq := &paymentsdk.OrderListRequest{
UserID: "user123",
Status: "2", // 已支付
Page: 1,
PageSize: 10,
}
listResp, err := client.GetOrderList(listReq)
if err == nil {
for _, order := range listResp.List {
fmt.Printf("订单: %s, 金额: %.2f\n", order.OrderNo, order.Amount)
}
}
取消订单与退款
err := client.CancelOrder(orderNo, "用户主动取消")
refundReq := &paymentsdk.RefundRequest{
OutTradeNo: orderNo,
RefundAmount: 0.01,
RefundReason: "商品质量问题",
}
refundResp, err := client.RefundOrder(refundReq)
订单状态说明
| 状态码 | 常量 | 说明 |
|---|---|---|
| 1 | OrderStatusNotPaid | 未支付 |
| 2 | OrderStatusScanned | 已扫码 |
| 101 | OrderStatusPaidFailed | 支付失败 |
| 201 | OrderStatusPaidSuccess | 支付成功 |
| 300 | OrderStatusClosed | 已关闭 |
| 400 | OrderStatusRefunded | 已退款 |
SDK 还提供了一组语义化的判断方法,写业务分支时更直观:
orderStatus, _ := client.QueryOrder(orderNo)
if orderStatus.IsPaymentSuccess() {
fmt.Println("支付成功")
}
if orderStatus.IsPaymentFailed() {
fmt.Println("支付失败")
}
if orderStatus.IsPending() {
fmt.Println("待支付")
}
if orderStatus.IsScanned() {
fmt.Println("已扫码")
}
if orderStatus.IsClosed() {
fmt.Println("已关闭")
}
if orderStatus.IsRefunded() {
fmt.Println("已退款")
}
错误处理
SDK 遵循 Go 常规的 error 返回约定,逐层判断即可:
paymentData, err := client.CreatePayment(req)
if err != nil {
// 处理错误
fmt.Printf("创建订单失败: %v\n", err)
return
}
// 使用 paymentData
高级配置
支付宝自定义返回地址(ReturnURL)
通过 ReturnURL 可以让不同业务跳转到不同页面,比如 VIP 充值跳会员中心、商品购买跳订单详情:
req := &paymentsdk.PaymentRequest{
Subject: "VIP会员充值",
Amount: 99.00,
PayWay: paymentsdk.PayWayAlipay,
ReturnURL: "https://mystore.com/vip/success?from=alipay&plan=monthly",
OrderType: "vip",
UserID: "user_12345",
}
paymentData, err := client.CreatePayment(req)
| 参数 | 类型 | 说明 |
|---|---|---|
| ReturnURL | string | 支付成功后的跳转地址(可选) |
常见使用场景:
- 不同商品不同页面 - VIP 充值跳转到会员中心,商品购买跳转到订单详情
- 携带自定义参数 - 在 URL 中携带来源、商品 ID 等信息
- 移动端和 PC 端区分 - 根据平台跳转到对应的成功页面
- A/B 测试 - 不同用户跳转到不同的落地页
注意事项:
- 不设置
ReturnURL时,使用服务端配置的默认返回地址 - 生产环境必须使用 HTTPS 协议,且地址需公网可访问
- 支付宝会在 URL 后追加支付结果参数(如
out_trade_no、trade_no等) - ReturnURL 是同步返回,仅用于页面展示,订单状态应以异步通知为准
- 建议在返回页面再次调用
QueryOrder验证订单状态
完整示例:
// 创建订单
req := &paymentsdk.PaymentRequest{
Subject: "iPhone 15 Pro",
Amount: 7999.00,
PayWay: paymentsdk.PayWayAlipay,
ReturnURL: "https://shop.example.com/order/success?product=iphone15",
OrderType: "product",
UserID: "user_67890",
}
paymentData, err := client.CreatePayment(req)
if err != nil {
return err
}
// 用户完成支付后会跳转到:
// https://shop.example.com/order/success?product=iphone15&out_trade_no=xxx&trade_no=xxx&...
// 在返回页面中,建议再次验证订单状态
orderStatus, err := client.QueryOrder(paymentData.OrderNo)
if err == nil && orderStatus.IsPaymentSuccess() {
// 显示支付成功页面
}
自定义 HTTP 客户端
需要调整连接池、超时等参数时,可以传入自己的 http.Client:
import "net/http"
customClient := &http.Client{
Timeout: 60 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
},
}
config := &paymentsdk.Config{
BaseURL: "https://api.example.com",
AppID: "your-app-id",
AppSecret: "your-app-secret",
HTTPClient: customClient,
}
client := paymentsdk.NewClient(config)
自定义轮询回调
在轮询过程中记录日志或做业务埋点,通过回调即可:
orderStatus, err := client.PollOrderStatus(orderNo, &paymentsdk.PollOptions{
Interval: 3 * time.Second,
MaxRetries: 20,
OnCheck: func(retry int, status *paymentsdk.OrderStatusData) {
log.Printf("[重试 %d] 订单 %s 状态: %s",
retry, status.OrderNo, paymentsdk.GetOrderStatusText(status.Status))
},
OnError: func(retry int, err error) {
log.Printf("[重试 %d] 查询失败: %v", retry, err)
},
})
并发安全
SDK 的所有方法都是线程安全的,多个 goroutine 可以放心共用同一个 Client 实例,无需额外加锁。
小结
整体来看,这套 SDK 把多通道支付的接入成本压得很低:初始化一次客户端,后续创建订单、查单、轮询、退款都走统一接口;签名认证(HMAC-SHA256)由 SDK 内部完成,不用自己处理。如果项目里正好要同时接支付宝、微信和 PayPal,值得直接上手试试。完整示例可参考仓库中的 example_usage.go 文件。