Golang中如何抽象支付网关的实现

Golang中如何抽象支付网关的实现 大家好,

我正在开发一个产品,需要集成多个支付网关。问题在于,我想为现有的众多支付网关创建一个抽象层。目前我需要处理以下网关:

  1. Paytm
  2. Razorpay
  3. Hyperpay
  4. Stripe
  5. Cybersource

目前我设计了以下抽象:

package gateway

type Gateway interface {
	GenerateKey(amount int)
	Save()
	Authorize()
	Payment
}

type Payment interface {
	Charge(amount int)
	Refund(paymentId int,amount int)
}

以上所有网关的行为方式各不相同,我希望能在同一个框架下实现它们。任何建议都将非常有帮助。


更多关于Golang中如何抽象支付网关的实现的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何抽象支付网关的实现的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中实现支付网关抽象,一个更完整的方案是定义清晰的接口层次结构。以下是一个经过实践检验的实现模式:

package payment

// 基础支付接口
type PaymentGateway interface {
    Authorize(request *AuthorizeRequest) (*AuthorizeResponse, error)
    Capture(request *CaptureRequest) (*CaptureResponse, error)
    Refund(request *RefundRequest) (*RefundResponse, error)
    Void(request *VoidRequest) (*VoidResponse, error)
    GetPaymentDetails(paymentID string) (*PaymentDetails, error)
}

// 特定网关能力接口
type Tokenizable interface {
    CreateToken(request *TokenRequest) (*TokenResponse, error)
    DeleteToken(tokenID string) error
}

type RecurringPayment interface {
    CreateSubscription(request *SubscriptionRequest) (*SubscriptionResponse, error)
    CancelSubscription(subscriptionID string) error
}

// 请求响应结构体
type AuthorizeRequest struct {
    Amount      int64
    Currency    string
    OrderID     string
    Customer    Customer
    PaymentMethod PaymentMethod
    Metadata    map[string]string
}

type AuthorizeResponse struct {
    TransactionID string
    Status        string
    AuthCode      string
    GatewayResponse interface{}
}

// 具体网关实现示例
type StripeGateway struct {
    client    *stripe.Client
    config    StripeConfig
    isSandbox bool
}

func (s *StripeGateway) Authorize(req *AuthorizeRequest) (*AuthorizeResponse, error) {
    params := &stripe.PaymentIntentParams{
        Amount:   stripe.Int64(req.Amount),
        Currency: stripe.String(req.Currency),
        PaymentMethodTypes: []*string{
            stripe.String("card"),
        },
        Metadata: req.Metadata,
    }
    
    pi, err := s.client.PaymentIntents.New(params)
    if err != nil {
        return nil, fmt.Errorf("stripe authorize failed: %w", err)
    }
    
    return &AuthorizeResponse{
        TransactionID: pi.ID,
        Status:        string(pi.Status),
        AuthCode:      pi.ClientSecret,
    }, nil
}

func (s *StripeGateway) Refund(req *RefundRequest) (*RefundResponse, error) {
    params := &stripe.RefundParams{
        PaymentIntent: stripe.String(req.PaymentID),
        Amount:        stripe.Int64(req.Amount),
    }
    
    refund, err := s.client.Refunds.New(params)
    if err != nil {
        return nil, fmt.Errorf("stripe refund failed: %w", err)
    }
    
    return &RefundResponse{
        RefundID: refund.ID,
        Status:   string(refund.Status),
    }, nil
}

// Razorpay网关实现
type RazorpayGateway struct {
    client *razorpay.Client
    config RazorpayConfig
}

func (r *RazorpayGateway) Authorize(req *AuthorizeRequest) (*AuthorizeResponse, error) {
    data := map[string]interface{}{
        "amount":   req.Amount,
        "currency": req.Currency,
        "receipt":  req.OrderID,
        "notes":    req.Metadata,
    }
    
    order, err := r.client.Order.Create(data, nil)
    if err != nil {
        return nil, fmt.Errorf("razorpay order creation failed: %w", err)
    }
    
    return &AuthorizeResponse{
        TransactionID: order["id"].(string),
        Status:        "created",
    }, nil
}

// 网关工厂
type GatewayType string

const (
    GatewayStripe     GatewayType = "stripe"
    GatewayRazorpay   GatewayType = "razorpay"
    GatewayPaytm      GatewayType = "paytm"
    GatewayHyperpay   GatewayType = "hyperpay"
    GatewayCybersource GatewayType = "cybersource"
)

type GatewayFactory struct {
    configs map[GatewayType]interface{}
}

func (f *GatewayFactory) CreateGateway(gatewayType GatewayType) (PaymentGateway, error) {
    switch gatewayType {
    case GatewayStripe:
        config := f.configs[gatewayType].(StripeConfig)
        client := stripe.NewClient(config.SecretKey)
        return &StripeGateway{
            client:    client,
            config:    config,
            isSandbox: config.IsSandbox,
        }, nil
        
    case GatewayRazorpay:
        config := f.configs[gatewayType].(RazorpayConfig)
        client := razorpay.NewClient(config.KeyID, config.KeySecret)
        return &RazorpayGateway{
            client: client,
            config: config,
        }, nil
        
    case GatewayPaytm:
        config := f.configs[gatewayType].(PaytmConfig)
        return NewPaytmGateway(config), nil
        
    default:
        return nil, fmt.Errorf("unsupported gateway type: %s", gatewayType)
    }
}

// 使用示例
func main() {
    factory := &GatewayFactory{
        configs: map[GatewayType]interface{}{
            GatewayStripe: StripeConfig{
                SecretKey: "sk_test_xxx",
                IsSandbox: true,
            },
            GatewayRazorpay: RazorpayConfig{
                KeyID:     "rzp_test_xxx",
                KeySecret: "xxx",
            },
        },
    }
    
    // 创建Stripe网关
    stripeGateway, err := factory.CreateGateway(GatewayStripe)
    if err != nil {
        log.Fatal(err)
    }
    
    // 执行支付授权
    authReq := &AuthorizeRequest{
        Amount:   1000, // 10.00 USD
        Currency: "USD",
        OrderID:  "order_123",
        Customer: Customer{
            Email: "customer@example.com",
        },
    }
    
    authResp, err := stripeGateway.Authorize(authReq)
    if err != nil {
        log.Printf("Authorization failed: %v", err)
    }
    
    fmt.Printf("Transaction ID: %s\n", authResp.TransactionID)
}

这个实现提供了以下关键特性:

  1. 统一的接口契约:所有网关实现相同的PaymentGateway接口
  2. 可选的能力接口:通过TokenizableRecurringPayment接口支持网关特定功能
  3. 标准化的请求响应:使用统一的结构体处理不同网关的差异
  4. 工厂模式:集中管理网关实例的创建
  5. 错误处理:统一错误包装,便于调试和监控
  6. 类型安全:使用具体类型避免interface{}滥用

对于不同网关的行为差异,可以在具体实现中处理。例如,Paytm可能需要额外的验证步骤,而Cybersource可能需要特定的风控数据。每个网关实现负责将自己的API适配到标准接口。

回到顶部