go-pay / gopay

微信、支付宝、通联支付、拉卡拉、PayPal、Apple 的Go版本SDK。【极简、易用的聚合支付SDK】
https://github.com/go-pay/gopay
Apache License 2.0
4.16k stars 721 forks source link

接收不到异步通知,完成支付以后收不到异步通知的请求 #413

Closed BJorah closed 4 weeks ago

BJorah commented 1 month ago

我写了一个简单的支付模块,使用电脑网站的支付接口,我发出一个POST请求,可以正常得到响应的支付url,我点进去也可以正常支付,但是支付完成后,没有跳转返回到我的页面,也收不到异步通知。 我在这里指定了异步通知的回调接口,但是支付完成后它并不执行我的回调函数 image

我的代码如下,可以帮我看一下是为什么吗?

func main() {

    initDB()
    initAlipayClient()

    r := gin.Default()

    // 处理支付相关的 API
    r.POST("/api/paycheck", HandlePayCheck)

        //就是这里,我完成支付以后它不执行我的这个回调函数
    r.POST("/api/alipay/notify", HandleAlipayNotify)
    r.GET("/alipay/return", func(c *gin.Context) {
        c.Header("Content-Type", "text/html")
        c.String(200, "<h1>Hello World</h1>")
    })

    // 启动服务器
    r.Run(":8080")
}
// 交易核算信息
var myOnePurchase = OnePurchase{
    AppID: "payinfo_01",
}

func HandlePayCheck(c *gin.Context) {
    var req PayCheckRequest

    //req的账号和金额是从请求中解析出来的
    if err := c.ShouldBindJSON(&req); err != nil {
        log.Fatal("req")
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
        return
    }

    //这里得到支付链接
    alipayUrl, err := GenerateAlipayPayment(payinfo_01.Id, req.Amount)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate Alipay URL"})
        return
    }
       //此处可以返回正确的支付链接,使用这个url可以正常支付
    c.JSON(http.StatusOK, gin.H{"alipay_url": alipayUrl})
}

func HandleAlipayNotify(c *gin.Context) {

    // 解析支付宝异步通知
    log.Println("开始处理支付宝异步通知")

    notifyReq, err := ParseAlipayNotify(c.Request)
    if err != nil {
        c.String(http.StatusBadRequest, "Invalid notification")
        return
    }

    //核对信息
    if notifyReq.AppID != myOnePurchase.AppID || notifyReq.OutTradeNo != myOnePurchase.OutTradeNo || notifyReq.TotalAmount != myOnePurchase.TotalAmount {
        // c.String(http.StatusBadRequest, "Invalid notification"){
        log.Fatal("交易信息错误")
    }
    //支付成功
    if notifyReq.TradeStatus == "TRADE_SUCCESS" {

        //更新数据库

    }
    c.String(http.StatusOK, "success")
}
//初始化支付宝客户端
func initAlipayClient() {
    var err error
    alipayClient, err = alipay.NewClient(your_app_id, your_private_key, false)
    if err != nil {
        log.Fatal("failed to create alipay client, err:", err)
        panic("failed to create alipay client")
    }
    // 打开Debug开关,输出日志,默认关闭
    alipayClient.DebugSwitch = gopay.DebugOn
    // 设置支付宝请求 公共参数
    alipayClient.SetLocation(alipay.LocationShanghai)
    // 用于用户支付完成后重定向到你的网站,通常是一个前端页面,展示支付结果。
    alipayClient.SetReturnUrl("127.0.0.1:8080/alipay/return")
    // 用于支付宝异步通知我的服务器支付结果,需要在后台处理这个请求,并更新订单状态。
    alipayClient.SetNotifyUrl("127.0.0.1:8080/api/alipay/notify")

    // 公钥证书模式,需要传入证书
    // 证书路径
    err = alipayClient.SetCertSnByPath("./cert/appPublicCert.crt", "./cert/alipayRootCert.crt", "./cert/alipayPublicCert.crt")
    if err != nil {
        log.Fatal("failed to set cert sn by path, err", err)
    }

}

// 调用支付宝接口生成支付链接
func GenerateAlipayPayment(orderID string, amount int) (string, error) {

    //构建请求参数
    bm := gopay.BodyMap{}
    bm.Set("subject", "订单支付").
        Set("out_trade_no", orderID).
        Set("total_amount", fmt.Sprintf("%.2f", float64(amount))).
        Set("product_code", "QUICK_MSECURITY_PAY")

    payUrl, err := alipayClient.TradePagePay(context.Background(), bm)
    if err != nil {
        return "", err
    }

    return payUrl, nil
}

type AlipayNotify struct {
    AppID       string
    OutTradeNo  string
    TotalAmount string
    TradeStatus string
}

// 解析支付宝的异步通知,并验证签名
// 接收到异步通知并验签通过后,请务必核对通知中的 app_id、out_trade_no、total_amount 等参数值是否与请求中的一致,
// 并根据 trade_status 进行后续业务处理。
func ParseAlipayNotify(req *http.Request) (*AlipayNotify, error) {
    bodyMap, err := alipay.ParseNotifyToBodyMap(req)
    if err != nil {
        return nil, err
    }

    // ok, err := alipay.VerifySign(, bodyMap)
    // 支付宝异步通知验签(公钥证书模式)
    ok, err := alipay.VerifySignWithCert("./cert/alipayPublicCert.crt", bodyMap)
    if err != nil || !ok {
        return nil, fmt.Errorf("invalid signature")
    }

    notify := &AlipayNotify{
        AppID:       bodyMap.Get("app_id"),
        OutTradeNo:  bodyMap.Get("out_trade_no"),
        TotalAmount: bodyMap.Get("total_amount"),
        TradeStatus: bodyMap.Get("trade_status"),
    }

    return notify, nil
}
iGoogle-ink commented 1 month ago

通知URL 要是 HTTPS 的公网可访问的接口地址,你那个明显不对啊 127.0.0.1:8080/api/alipay/notify 这地址,支付宝怎么可能请求通你的服务?

BJorah commented 4 weeks ago

通知URL 要是 HTTPS 的公网可访问的接口地址,你那个明显不对啊 127.0.0.1:8080/api/alipay/notify 这地址,支付宝怎么可能请求通你的服务?

嗷嗷好的,感谢!