diff --git a/app/main/api/internal/logic/pay/paymentlogic.go b/app/main/api/internal/logic/pay/paymentlogic.go index 24ed7ab..28548b9 100644 --- a/app/main/api/internal/logic/pay/paymentlogic.go +++ b/app/main/api/internal/logic/pay/paymentlogic.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "os" + "strings" "time" "tyc-server/app/main/api/internal/svc" "tyc-server/app/main/api/internal/types" @@ -35,6 +36,21 @@ type PaymentTypeResp struct { payMerchantID string } +// prepayDataMissing 判断第三方支付预创建是否未返回可用参数(含 interface 包了一层 nil 的情况) +func prepayDataMissing(v interface{}) bool { + if v == nil { + return true + } + switch t := v.(type) { + case string: + return t == "" + case map[string]string: + return len(t) == 0 + default: + return false + } +} + func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic { return &PaymentLogic{ Logger: logx.WithContext(ctx), @@ -44,6 +60,10 @@ func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLo } func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) { + req.PayMethod = strings.TrimSpace(req.PayMethod) + req.PayType = strings.TrimSpace(req.PayType) + req.Id = strings.TrimSpace(req.Id) + var paymentTypeResp *PaymentTypeResp var prepayData interface{} l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { @@ -90,6 +110,21 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, if createOrderErr != nil { return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr) } + // 在事务内校验并失败则回滚,避免订单已落库却无 prepay(此前仅事务外校验会产生脏订单) + if req.PayMethod == "wechat" || req.PayMethod == "alipay" { + if prepayDataMissing(prepayData) { + platformVal := l.ctx.Value("platform") + logx.WithContext(l.ctx).Errorf( + "[Payment] 事务内 prepay 为空将回滚: pay_method=%q pay_type=%q order_no=%s platform=%v prepayData_type=%T", + req.PayMethod, req.PayType, paymentTypeResp.outTradeNo, platformVal, prepayData, + ) + return errors.Wrapf( + xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, "获取支付参数失败,请确认在微信内打开且已完成网页授权后重试"), + "创建支付失败: prepay 为空 platform=%v", + platformVal, + ) + } + } return nil }) if err != nil { @@ -97,8 +132,13 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, } if req.PayMethod == "wechat" || req.PayMethod == "alipay" { - if prepayData == nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建支付失败: 未生成支付参数") + if prepayDataMissing(prepayData) { + logx.WithContext(l.ctx).Errorf("[Payment] 事务提交后 prepay 仍为空(不应出现): pay_method=%q id=%q platform=%v", + req.PayMethod, req.Id, l.ctx.Value("platform")) + return nil, errors.Wrapf( + xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, "获取支付参数失败,请稍后重试"), + "创建支付失败: 未生成支付参数", + ) } } diff --git a/app/main/api/internal/middleware/global_sourceinterceptor_middleware.go b/app/main/api/internal/middleware/global_sourceinterceptor_middleware.go index c7197b3..f2974ab 100644 --- a/app/main/api/internal/middleware/global_sourceinterceptor_middleware.go +++ b/app/main/api/internal/middleware/global_sourceinterceptor_middleware.go @@ -3,6 +3,7 @@ package middleware import ( "context" "net/http" + "strings" ) const ( @@ -12,7 +13,7 @@ const ( func GlobalSourceInterceptor(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // 获取请求头 X-Platform 的值 - platform := r.Header.Get(PlatformKey) + platform := strings.TrimSpace(r.Header.Get(PlatformKey)) // 将值放入新的 context 中 ctx := r.Context() diff --git a/app/main/api/internal/service/wechatpayService.go b/app/main/api/internal/service/wechatpayService.go index 935e969..3c5b2d3 100644 --- a/app/main/api/internal/service/wechatpayService.go +++ b/app/main/api/internal/service/wechatpayService.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "strconv" + "strings" "time" "tyc-server/app/main/api/internal/config" "tyc-server/app/main/model" @@ -273,10 +274,14 @@ func (w *WechatPayService) CreateWechatH5Order(ctx context.Context, amount float func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64, description string, outTradeNo string) (interface{}, error) { platformVal := ctx.Value("platform") platform, ok := platformVal.(string) + platform = strings.TrimSpace(platform) if !ok || platform == "" { + logx.WithContext(ctx).Errorf("[WechatPay] CreateWechatOrder 缺少 X-Platform") return "", fmt.Errorf("缺少 X-Platform 请求头(微信内请传 wxh5)") } + logx.WithContext(ctx).Infof("[WechatPay] CreateWechatOrder platform=%q out_trade_no=%s", platform, outTradeNo) + var prepayData interface{} var err error @@ -319,6 +324,10 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64 return "", fmt.Errorf("支付订单创建失败: %v", err) } + if prepayData == nil { + logx.WithContext(ctx).Errorf("[WechatPay] CreateWechatOrder 返回 prepayData 为 nil platform=%q", platform) + } + // 返回预支付ID return prepayData, nil }