本文章主要是通過golang實現了支付寶手機網頁支付的簡單封裝,封裝的基本都是請求的必傳參數,如果需要其他參數,可以自己修改BizContent結構體來滿足自己的需求。
封裝的文件大體分爲4個文件:
config.go 用來放基本配置參數,現在只放了需要用的rsa用戶私鑰和阿里rsa公鑰,其中用戶私鑰本封裝文件用的pkcs8的,你也可以修改爲pkcs1的
dao.go 主要是存放了BizConten結構體,裏面只有必傳參數,可以自行修改
sign.go 主要是生成簽名字符串的,生成正確會返回一個字符串
pay.go 主要的封裝文件,實現了post請求,通過調用pay方法會返回一個編碼後的body體(返回的是個網頁直接輸出到頁面就好),還有一個err參數,正確返回nil
大致項目結構如下:
config.go文件 :
package alipay
const (
private_key = ``
alipay_public_key = ``
)
dao.go 文件 :在實際操作中,我們需要對金額做一些處理,不能直接用float,這會導致有時數據不對。在此可以使用github.com/shopspring/decimal,或者直接金額一般到分直接用戶分爲單位採用整型
package alipay
type BizContent struct {
Subject string `json:"subject"`
OutTradeNo string `json:"out_trade_no"`
TotalAmount float32 `json:"total_amount"`
ProductCode string `json:"product_code"`
}
sign.go 文件:通過修改rsaEncrypt方法中的x509.ParsePKCS8PrivateKey(block2.Bytes),修改爲x509.ParsePKCS1PrivateKey(block2.Bytes),這樣就可以使用pkcs1的鑰匙
package alipay
import (
"sort"
"fmt"
"encoding/base64"
"encoding/pem"
"crypto/x509"
"crypto/rsa"
"crypto/sha256"
"crypto"
"net/url"
"crypto/rand"
)
func sign(m url.Values) string {
//對url.values進行排序
sign := ""
var keys []string
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for i, k := range keys {
if m.Get(k) != "" {
if i==0{
sign = k+"="+m.Get(k)
}else {
sign = sign + "&"+ k+"="+m.Get(k)
}
}
}
fmt.Println(sign)
//對排序後的數據進行rsa2加密,獲得sign
b,_ := rsaEncrypt([]byte(sign))
fmt.Println("加密:",b)
fmt.Println("base加密:",base64.StdEncoding.EncodeToString(b))
return base64.StdEncoding.EncodeToString(b)
}
func rsaEncrypt(origData []byte) ([]byte, error) {
key := private_key
block2, _ := pem.Decode([]byte(key))//PiravteKeyData爲私鑰文件的字節數組
if block2 == nil {
fmt.Println("block空")
return nil,nil
}
//priv即私鑰對象,block2.Bytes是私鑰的字節流
priv, err := x509.ParsePKCS8PrivateKey(block2.Bytes)
if err != nil {
fmt.Println("無法還原私鑰")
return nil,nil
}
p := priv.(*rsa.PrivateKey)
h2 := sha256.New()
h2.Write(origData)
hashed := h2.Sum(nil)
signature2, err := rsa.SignPKCS1v15(rand.Reader, p,
crypto.SHA256, hashed)//簽名
return signature2,err
}
pay.go 文件:
package alipay
import (
"net/url"
"time"
"net/http"
"fmt"
"io/ioutil"
"github.com/axgle/mahonia"
)
func Pay(appId string,returnUrl string,notifyUrl string,bizContent string) (s string,err error) {
var data = url.Values{}
//var clusterinfo = map[string]string{}
data.Add("app_id", appId)
data.Add("method", "alipay.trade.wap.pay")
if returnUrl != "" {
data.Add("return_url",returnUrl)
}
if notifyUrl != "" {
data.Add("notify_url", returnUrl)
}
data.Add("format", "json")
data.Add("charset", "UTF-8")
data.Add("sign_type", "RSA2")
data.Add("timestamp", time.Now().Format("2006-01-02 15:04:05"))
data.Add("version", "1.0")
data.Add("biz_content",bizContent)
data.Add("sign", sign(data))
resp, err := http.PostForm("https://openapi.alipay.com/gateway.do",data)
defer resp.Body.Close()
if err != nil {
fmt.Println(err)
return "",err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return "",err
}
d := mahonia.NewDecoder("utf-8")
return d.ConvertString(string(body)),err
}
調用方法,在你需要調用的方法中加入以下代碼即可,例如:
func ali(c echo.Context) error {
bizContent := new(alipay.BizContent)
bizContent.Subject = "ceshi"
bizContent.OutTradeNo = "1111112312312312312"
bizContent.TotalAmount = 0.01
bizContent.ProductCode = "QUICK_WAP_WAY"
e,err := json.Marshal(bizContent)
if err != nil {
return err
}
body,err := alipay.Pay("","","",string(e))
if err != nil {
return err
}
return c.HTML(200,body)
}