golang调用蓝兔支付实现网上支付功能

 更新时间:2023年09月19日 10:36:58   作者:唐诗  
支付宝、微信的网上支付需要营业执照个人无法直接使用,如果个人需要实现网上支付功能,目前大部分应该是都是依赖第三方聚合支付来实现,本文就来介绍一下如何调用蓝兔支付实现网上支付功能,有需要的可以参考下

支付宝、微信的网上支付需要营业执照个人无法直接使用。

如果个人需要实现网上支付功能,目前大部分应该是都是依赖第三方聚合支付来实现。

三方聚合支付

我是在做一个电商网站(ps:极简风格)的 demo 所以并不会有太多的流水,经过一番检索我发现大部分三方支付都会收取一些费用比如开户费、接口服务服务费。

咱也能理解毕竟靠爱发电不是长久的事情,有时候支付一些费用获取比较好的体验也是可以接受的。

矮个子里挑高个我找到了蓝兔支付-猛击访问官网 开户费用 50,相对来说比较优惠了。

接口服务费感觉有那么一点高,不过我是用来做个人网站的支付不会有太大的流水倒也没那么在意。

产品对比

从这张图大概可以了解到与微信官方的一些区别。

商户开通

蓝兔支付的开通还是比较简单的进入个人中心、点击微信支付申请签约。

然后你会看到一个弹窗,小伙子你很刚啊!

然后按照要求填写一些信息即可,身份信息需要上传身份证照片。

友情提示记得加水印养成好习惯!

都做完以后一般很快就会审核完成,我大概半个小时左右就可以了。

然后在商户管理这里可以看到商户号、商户密钥后边调用接口要用!

使用 go 对接蓝兔支付

蓝兔支付提供了对接文档文档地址这非常好,一个好的文档可以让我少走很多弯路。

实现签名算法

这里文档说明了签名算法的实现,说明了和微信支付的签名算法一致可以使用微信支付的校验工具进行测试。

可以测试就会简单很多,让我们来实现一下这个签名。

package pay  
import (  
    "crypto/md5"  
    "encoding/hex"  
    "simple-mall/global"  
    "sort"  
    "strings"  
)  
func calculateMD5(data string) string {  
    hash := md5.Sum([]byte(data))  
    return hex.EncodeToString(hash[:])  
}  
// LTZFGenerateSignature 生成蓝兔支付签名  
func LTZFGenerateSignature(sinObj map[string]string) string {  
    // 按照参数名进行字典序排序  
    keys := make([]string, 0, len(sinObj))  
    for k := range sinObj {  
        keys = append(keys, k)  
    }  
    sort.Strings(keys)  
    // 拼接参数键值对  
    var builder strings.Builder  
    for _, key := range keys {  
    value := sinObj[key]  
        if value != "" {  
            builder.WriteString(key + "=" + value + "&")  
        }  
    }  
    // 拼接密钥 也就上边说的商户密钥
    builder.WriteString("key=" + global.LTZFConfig.SecretKey)  
    // 计算MD5并转换为大写  
    signature := calculateMD5(builder.String())  
    return strings.ToUpper(signature)  
}

支付接口参数序列化

接口的调用比较简单但是没有接口参数的示例,参考文档实现下参数的封装。

// 获取微信支付签名对象  
func getLTZFWeChatPayApiSinObj(params map[string]string) string {  
    // 只有必填参数才参与签名!
    sinObj := map[string]string{  
        "mch_id": params["mch_id"],  
        "out_trade_no": params["out_trade_no"],  
        "total_fee": params["total_fee"],  
        "body": params["body"],  
        "timestamp": params["timestamp"],  
        "notify_url": params["notify_url"],  
    }  
    return LTZFGenerateSignature(sinObj)  
}
// 获取蓝兔支付微信 api 参数  
func getLTZFWeChatPayApiReq(payReq pay.WeChatPayReq) url.Values {  
    // 请求支付接口参数  
    opts := map[string]string{  
        "mch_id": global.LTZFConfig.MchId, // 上边说的商户id  
        "out_trade_no": payReq.OrderId,
        "total_fee": "0.01", // 为了测试设置为 0.01 防止误支付
        "body": payReq.Info,  
        "timestamp": strconv.FormatInt(time.Now().Unix(), 10),  
        "notify_url": "xxxxx",  // 这里填写支付成功的回调地址
        "attach": payReq.OrderId,  // 附加数据,在支付通知中原样返回
        "time_expire": "15m",  // 支付超时时间
        "sign": "",  
    }  
    // 设置接口签名  
    opts["sign"] = getLTZFWeChatPayApiSinObj(opts)  
    // 格式化参数  
    req := url.Values{}  
    for key, value := range opts {  
        req.Add(key, value)  
    }  
    return req  
}

支付接口调用

支付接口的调用官网文档有示例,记得先设置白名单地址。

咱就借鉴官网的调用示例然后完善一下,这里使用了 gin。

func WeChatPay(ctx *gin.Context) {  
    payReq := pay.WeChatPayReq{}  
    if err := ctx.ShouldBind(&payReq); err != nil {  
        utils.HandleValidatorError(ctx, err)  
        return  
    }  
    // 调用蓝兔支付接口 获取支付二维码
    res, err := http.PostForm("https://api.ltzf.cn/api/wxpay/native", getLTZFWeChatPayApiReq(payReq))  
    if err != nil {  
        // 处理请求错误  
        utils.ResponseResultsError(ctx, err.Error())  
        return  
    }  
    defer func(Body io.ReadCloser) {  
    err := Body.Close()  
    if err != nil {  
        utils.ResponseResultsError(ctx, err.Error())  
    }  
    }(res.Body)  
    body, err := io.ReadAll(res.Body)  
    if err != nil {  
        // 处理读取响应体错误  
        utils.ResponseResultsError(ctx, err.Error())  
        return  
    }  
    // 解析接口响应数据  
    type Data struct {  
        CodeURL string `json:"code_url"`  
        QRCodeURL string `json:"QRcode_url"`  
    }  
    type Response struct {  
        Code int `json:"code"`  
        Data Data `json:"data"`  
        Msg string `json:"msg"`  
        RequestID string `json:"request_id"`  
    }  
    // 解析JSON数据  
    var resp Response  
    if err := json.Unmarshal(body, &resp); err != nil {  
        // 处理解析JSON错误  
        utils.ResponseResultsError(ctx, err.Error())  
        return  
    }  
    if resp.Code != 0 {  
        utils.ResponseResultsError(ctx, resp.Msg)  
        return  
    }  
    utils.ResponseResultsSuccess(ctx, resp.Data)  
}

然后也提供了一个交易记录的管理。

总结

文章介绍了使用 go + 蓝兔支付 来实现的个人的网上支付,从蓝兔支付的开通到对接这个过程做了一个讲解说明。

重点说明:蓝兔支付客服态度不是很友好!

以上就是golang调用蓝兔支付实现网上支付功能的详细内容,更多关于go支付的资料请关注脚本之家其它相关文章!

相关文章

  • 使用Golang进行比较版本号大小

    使用Golang进行比较版本号大小

    在日常开发中,比较版本号大小的情况是经常遇到的,这篇文章主要为大家详细介绍了如何使用Golang进行比较版本号大小,需要的小伙伴可以参考下
    2024-01-01
  • Go语言strconv包实现字符串和数值类型的相互转换

    Go语言strconv包实现字符串和数值类型的相互转换

    这篇文章主要介绍了Go语言strconv包实现字符串和数值类型的相互转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • go语言中slice,map,channl底层原理

    go语言中slice,map,channl底层原理

    这篇文章主要介绍了go语言中slice,map,channl底层原理,slice,map,channl是我们Go语言中最最常用的几个数据结构,对于其更多相关内容需要的小伙伴可以参考下面文章详细内容
    2022-06-06
  • Go自定义数据序列化的流程详解

    Go自定义数据序列化的流程详解

    在Go语言中,自定义数据的序列化是一个常见的需求,本文将深入探讨 Go 语言中自定义数据序列化的流程,包括关键概念、技巧和最佳实践,旨在帮助开发者更高效地进行数据序列化工作,需要的朋友可以参考下
    2024-06-06
  • 使用go实现常见的数据结构

    使用go实现常见的数据结构

    这篇文章主要介绍了使用go实现常见的数据结构,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • go语言for循环中嵌套defer的执行顺序

    go语言for循环中嵌套defer的执行顺序

    在Go语言中,defer语句用于延迟函数调用的执行,本文主要介绍了go语言for循环中嵌套defer的执行顺序,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • golang jwt+token验证的实现

    golang jwt+token验证的实现

    这篇文章主要介绍了golang jwt+token验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • Go语言实现请求超时处理的方法总结

    Go语言实现请求超时处理的方法总结

    这篇文章主要为大家详细介绍了Go语言中实现请求的超时控制的方法,主要是通过timer和timerCtx来实现请求的超时控制,希望对大家有所帮助
    2023-05-05
  • golang多维度排序及题解最长连续序列

    golang多维度排序及题解最长连续序列

    这篇文章主要为大家介绍了golang多维度排序及题解最长连续序列示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Golang切片Slice功能操作详情

    Golang切片Slice功能操作详情

    这篇文章主要介绍了Golang切片功能操作详情,切片是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封,切片是一个引用类型,它的内部结构包含地址、长度和容量
    2022-09-09

最新评论