支付宝、微信的网上支付需要营业执照个人无法直接使用。
如果个人需要实现网上支付功能,目前大部分应该是都是依赖第三方聚合支付来实现。
三方聚合支付
我是在做一个电商网站(ps:极简风格)的 demo 所以并不会有太多的流水,经过一番检索我发现大部分三方支付都会收取一些费用比如开户费、接口服务服务费。
咱也能理解毕竟靠爱发电不是长久的事情,有时候支付一些费用获取比较好的体验也是可以接受的。
矮个子里挑高个我找到了蓝兔支付-猛击访问官网 开户费用 50
,相对来说比较优惠了。
接口服务费感觉有那么一点高,不过我是用来做个人网站的支付不会有太大的流水倒也没那么在意。
产品对比
从这张图大概可以了解到与微信官方的一些区别。
商户开通
蓝兔支付的开通还是比较简单的进入个人中心、点击微信支付申请签约。
然后你会看到一个弹窗,小伙子你很刚啊!
然后按照要求填写一些信息即可,身份信息需要上传身份证照片。
友情提示记得加水印养成好习惯!
都做完以后一般很快就会审核完成,我大概半个小时左右就可以了。
然后在商户管理这里可以看到商户号、商户密钥后边调用接口要用!
使用 go 对接蓝兔支付
蓝兔支付提供了对接文档文档地址这非常好,一个好的文档可以让我少走很多弯路。
实现签名算法
这里文档说明了签名算法的实现,说明了和微信支付的签名算法一致可以使用微信支付的校验工具进行测试。
可以测试就会简单很多,让我们来实现一下这个签名。
golang
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)
}
支付接口参数序列化
接口的调用比较简单但是没有接口参数的示例,参考文档实现下参数的封装。
golang
// 获取微信支付签名对象
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。
golang
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 + 蓝兔支付 来实现的个人的网上支付,从蓝兔支付的开通到对接这个过程做了一个讲解说明。
重点说明:蓝兔支付客服态度不是很友好!