[Golang] 纯文本查看 复制代码
package main
import (
"fmt"
"net/http"
"net/url"
"strconv"
"time"
)
func main() {
// 支付宝应用ID
appId := ""
// 商户私钥
privateKey := ""
// 支付宝公钥
publicKey := ""
// 支付金额,单位为元
amount := 0.01
// 订单号
orderId := "1234567890"
// 商品简称
subject := "测试商品"
// 构造请求参数
values := url.Values{}
values.Set("app_id", appId)
values.Set("method", "alipay.trade.precreate")
values.Set("format", "JSON")
values.Set("charset", "utf-8")
values.Set("sign_type", "RSA2")
values.Set("timestamp", time.Now().Format("2006-01-02 15:04:05"))
values.Set("version", "1.0")
bizContent := fmt.Sprintf(`{"out_trade_no":"%s","total_amount":"%.2f","subject":"%s"}`, orderId, amount, subject)
values.Set("biz_content", bizContent)
// 计算签名
sign := calculateSign(values, privateKey)
// 添加签名
values.Set("sign", sign)
// 发送请求
resp, err := http.PostForm("https://openapi.alipay.com/gateway.do", values)
if err != nil {
fmt.Println("Error:", err)
return
}
// 解析响应
qrCodeUrl, err := parseResponse(resp, publicKey)
if err != nil {
fmt.Println("Error:", err)
return
}
// 打印二维码 URL
fmt.Println(qrCodeUrl)
}
// 计算签名
func calculateSign(values url.Values, privateKey string) string {
signStr := getSignString(values)
sign, err := signWithRSA2(signStr, privateKey)
if err != nil {
fmt.Println("Error:", err)
return ""
}
return sign
}
// 解析响应
func parseResponse(resp *http.Response, publicKey string) (string, error) {
var respMap map[string]interface{}
err := parseJsonResp(resp, &respMap)
if err != nil {
return "", err
}
if respMap["alipay_trade_precreate_response"] == nil {
return "", fmt.Errorf("Invalid response: %v", respMap)
}
if respMap["alipay_trade_precreate_response"].(map[string]interface{})["code"].(string) != "10000" {
return "", fmt.Errorf("%s: %s", respMap["alipay_trade_precreate_response"].(map[string]interface{})["sub_msg"].(string),
respMap["alipay_trade_precreate_response"].(map[string]interface{})["msg"].(string))
}
qrCodeUrl := respMap["alipay_trade_precreate_response"].(map[string]interface{})["qr_code"].(string)
isSuccess, err := verifyRespSign(respMap["alipay_trade_precreate_response"].(map[string]interface{}), publicKey)
if !isSuccess {
return "", err
}
return qrCodeUrl, nil
}
// 构造待签名字符串
func getSignString(values url.Values) string {
keys := make([]string, 0, len(values))
for k := range values {
if k == "sign" || k == "sign_type" {
continue
}
keys = append(keys, k)
}
sortedKeys := sortKeys(keys)
var signStr string
for i, k := range sortedKeys {
if i == 0 {
signStr = k + "=" + values.Get(k)
} else {
signStr += "&" + k + "=" + values.Get(k)
}
}
return signStr
}
// 对参数进行字典序排序
func sortKeys(keys []string) []string {
sorted := make([]string, len(keys))
copy(sorted, keys)
for i := 0; i < len(sorted)-1; i++ {
for j := i + 1; j > 0; j-- {
if sorted[j-1] > sorted[j] {
sorted[j], sorted[j-1] = sorted[j-1], sorted[j]
} else {
break
}
}
}
return sorted
}
// 使用RSA2算法签名
func signWithRSA2(signStr string, privateKey string) (string, error) {
signer, err := NewSigner(privateKey)
if err != nil {
return "", err
}
return signer.Sign(signStr)
}
// 验证响应签名
func verifyRespSign(respMap map[string]interface{}, publicKey string) (bool, error) {
sign := respMap["sign"].(string)
signType := respMap["sign_type"].(string)
delete(respMap, "sign")
delete(respMap, "sign_type")
signStr := getSignStringFromMap(respMap)
verifier := NewVerifier(publicKey, signType)
return verifier.Verify(signStr, sign)
}
// 获取待签名字符串
func getSignStringFromMap(m map[string]interface{}) string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sortedKeys := sortKeys(keys)
signStr := ""
for i, k := range sortedKeys {
if i == 0 {
signStr = k + "=" + fmt.Sprintf("%v", m[k])
} else {
signStr += "&" + k + "=" + fmt.Sprintf("%v", m[k])
}
}
return signStr
}