1. Preparation phase
pc&h5 access steps
Official Document /docList...
View the main access steps
Key generation
• Desc key needs to be set
• md5 key and app id app docking will be used
• Certificate file name
my_rsa_private_pkcs8_key.pem wy_rsa_public_key.pem
The sample program uses the private key format as pkcs8 format
The data in the official SDK can be used in the sample program
Download SDK address /docList...
Find the demo in the interface document
Packages that will be used
import ( "encoding/base64" "encoding/json" "encoding/xml" "errors" "fmt" "io/ioutil" "net/http" "os" "strconv" "strings" "time" )
Encrypt, decrypt, verify signature
package main import ( "bytes" "crypto" "crypto/des" cryptoRand "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/hex" "encoding/pem" "errors" "fmt" "math/rand" "regexp" "sort" "strings" "time" ) func randNumber() string { return ("%05v", ((().UnixNano())).Int31n(100000)) } func checkSign(decryptBytes []byte, sign, publicKey string) bool { decrypt := string(decryptBytes) clipStartIndex := (decrypt, "<sign>") clipEndIndex := (decrypt, "</sign>") xmlStart := decrypt[0:clipStartIndex] xmlEnd := decrypt[clipEndIndex+7 : len(decrypt)] originXml := xmlStart + xmlEnd //Signature verification if sign == "" { return false } return checkRsaSign(originXml, publicKey, sign) } func replaceXmlStrBlankChar(str string) string { str = (str, "\r", "", -1) str = (str, "\n", "", -1) str = (str, "\t", "", -1) reg, _ := (">\\s+<") str = (str, "><") reg, _ = ("\\s+\\/>") str = (str, "/>") return str } func getPaySign(paramMap map[string]string, privateKey string) (string, error) { payString := getSortString(paramMap) return getRsaSign(payString, privateKey) } // ------ // Encryptionfunc encrypt3DES(paramMap map[string]string, desKey string) (map[string]string, error) { desKey = base64DecodeStr(desKey) for k, v := range paramMap { if k == "sign" || k == "merchant" || k == "version" { continue } encrypt, err := tripleEcbDesEncrypt([]byte(v), []byte(desKey)) if err != nil { return paramMap, err } paramMap[k] = decimalByteSlice2HexString(encrypt) } return paramMap, nil } func decryptArg(notifyQuery NotifyQuery, desKey string) (decryptBytes []byte, err error) { desKeyBytes, err := (desKey) if err != nil { return nil, err } encryptBytes, err := () if err != nil { return nil, err } encryptBytes, err = hexString2Bytes(string(encryptBytes)) if err != nil { return nil, err } decryptBytes, err = tripleEcbDesDecrypt(encryptBytes, desKeyBytes) if err != nil { return nil, err } return decryptBytes, nil } // JDAPP fill rulesfunc jdPadding(origData []byte) []byte { merchantData := len(origData) x := (merchantData + 4) % 8 y := 0 if x == 0 { y = 0 } else { y = 8 - x } sizeByte := integerToBytes(merchantData) var resultByte []byte //Fill in byte data length for i := 0; i < 4; i++ { resultByte = append(resultByte, sizeByte[i]) } //Fill in the original data length for j := 0; j < merchantData; j++ { resultByte = append(resultByte, origData[j]) } //Fill 0 for k := 0; k < y; k++ { resultByte = append(resultByte, 0x00) } return resultByte } func jdUnPadding(unPaddingResult []byte) []byte { var Result []byte var dataSizeByte []byte for i := 0; i < 4; i++ { dataSizeByte = append(dataSizeByte, unPaddingResult[i]) } decimalDataSize := byteArrayToInt(dataSizeByte) for j := 0; j < decimalDataSize; j++ { Result = append(Result, unPaddingResult[4+j]) } return Result } // The actual length represented by the byte arrayfunc byteArrayToInt(dataSizeByte []byte) int { value := 0 for i := 0; i < 4; i++ { shift := byte((4 - 1 - i) * 8) value = value + int(dataSizeByte[i]&0x000000FF)<<shift } return value } func integerToBytes(val int) [4]byte { byt := [4]byte{} byt[0] = byte(val >> 24 & 0xff) byt[1] = byte(val >> 16 & 0xff) byt[2] = byte(val >> 8 & 0xff) byt[3] = byte(val & 0xff) return byt } // byte to hexadecimal stringfunc decimalByteSlice2HexString(DecimalSlice []byte) string { var sa = make([]string, 0) for _, v := range DecimalSlice { sa = append(sa, ("%02X", v)) } ss := (sa, "") return ss } // Hexadecimal string to bytefunc hexString2Bytes(str string) ([]byte, error) { Bys, err := (str) if err != nil { return nil, err } return Bys, nil } // base decodingfunc base64DecodeStr(src string) string { a, err := (src) if err != nil { return "" } return string(a) } // Des decryptionfunc decrypt(crypted, key []byte) ([]byte, error) { if len(crypted) < 1 || len(key) < 1 { return nil, ("wrong data or key") } block, err := (key) if err != nil { return nil, err } out := make([]byte, len(crypted)) dst := out bs := () if len(crypted)%bs != 0 { return nil, ("wrong crypted size") } for len(crypted) > 0 { (dst, crypted[:bs]) crypted = crypted[bs:] dst = dst[bs:] } return out, nil } // [golang ECB 3DES Decrypt] func tripleEcbDesDecrypt(crypted, key []byte) ([]byte, error) { tkey := make([]byte, 24, 24) copy(tkey, key) k1 := tkey[:8] k2 := tkey[8:16] k3 := tkey[16:] buf1, err := decrypt(crypted, k3) if err != nil { return nil, err } buf2, err := encrypt(buf1, k2) if err != nil { return nil, err } out, err := decrypt(buf2, k1) if err != nil { return nil, err } out = jdUnPadding(out) return out, nil } // sha256 encryptionfunc hasha256(str string) string { h := () ([]byte(str)) cipherStr := (nil) //return cipherStr return (cipherStr) } // Base decodingfunc base64EncodeStr(src string) string { return ([]byte(src)) } // Digitally sign the hash value of the messagefunc signPKCS1v15(msg, privateKey []byte, hashType ) ([]byte, error) { block, _ := (privateKey) if block == nil { return nil, ("private key format error") } pri, err := x509.ParsePKCS8PrivateKey() if err != nil { return nil, ("parse private key error") } key, ok := pri.(*) if ok == false { return nil, ("private key format error") } sign, err := rsa.SignPKCS1v15(, key, hashType, msg) if err != nil { return nil, ("sign error") } return sign, nil } // Des encryptionfunc encrypt(origData, key []byte) ([]byte, error) { if len(origData) < 1 || len(key) < 1 { return nil, ("wrong data or key") } block, err := (key) if err != nil { return nil, err } bs := () if len(origData)%bs != 0 { return nil, ("wrong padding") } out := make([]byte, len(origData)) dst := out for len(origData) > 0 { (dst, origData[:bs]) origData = origData[bs:] dst = dst[bs:] } return out, nil } // [golang ECB 3DES Encrypt] func tripleEcbDesEncrypt(origData, key []byte) ([]byte, error) { tkey := make([]byte, 24, 24) copy(tkey, key) k1 := tkey[:8] k2 := tkey[8:16] k3 := tkey[16:] origData = jdPadding(origData) // PKCS5Padding(origData, bs) buf1, err := encrypt(origData, k1) if err != nil { return nil, err } buf2, err := decrypt(buf1, k2) if err != nil { return nil, err } out, err := encrypt(buf2, k3) if err != nil { return nil, err } return out, nil } // ------------ // Verify the signaturefunc verifyPKCS1v15(msg, sign, publicKey []byte, hashType ) bool { block, _ := (publicKey) if block == nil { return false } pub, err := () if err != nil { panic(err) } err = rsa.VerifyPKCS1v15(pub.(*), hashType, msg, sign) return err == nil } func getRsaSign(paramStr string, privateKey string) (string, error) { sha256Str := hasha256(paramStr) sign, err := signPKCS1v15([]byte(sha256Str), []byte(privateKey), (0)) if err != nil { return "", err } base64String := (sign) return base64String, nil } func checkRsaSign(paramStr string, publicKey, sign string) bool { signByte, err := (sign) if err != nil { return false } sha256Str := hasha256(paramStr) return verifyPKCS1v15([]byte(sha256Str), signByte, []byte(publicKey), (0)) } // ------- // String stitching// Payment string stitchingfunc getSortString(m map[string]string) string { var buf keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } (keys) for _, k := range keys { vs := m[k] if () > 0 { ('&') } (k) ('=') (vs) } return () }
Loading the key in the program
func getKey(keyType string) (string, error) { keyMap := map[string]string{ "private_key": "./", "public_key": "./", } path, ok := keyMap[keyType] if !ok { return "", ("key path not exists") } fileHandler, err := (path) if err != nil { return "", err } defer () keyBytes, err := (fileHandler) if err != nil { return "", err } return string(keyBytes), nil }
2. Initiate payment
constant
constant const version = "V2.0" // JD Payment Versionconst merchantId = "" // Merchant IDconst desKey = "" // desc key const timeLayout = "20060102150405" const cny = "CNY" const practicalityGoodsType = "GT01" //Product type-Practical itemconst businessServiceConsumeCode = "100001" const practicality = "0" //Product Type-Real things
Call online payment interface
pc h5 initiates payment
Official Document /docList...
type Order struct { OrderId string `json:"order_id"` Amount float64 `json:"amount"` Items []*OrderItem `json:"items"` ShippingAddress *OrderShippingAddress `json:"shipping_address"` } type OrderItem struct { GoodsNo string `json:"goods_no"` GoodsName string `json:"goods_name"` GoodsPrice float64 `json:"goods_price"` GoodsNum uint32 `json:"goods_num"` } type OrderShippingAddress struct { Name string `json:"name"` Mobile string `json:"mobile"` Address string `json:"address"` Province string `json:"province"` City string `json:"city"` Country string `json:"country"` } type ReqWithEncrypt struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` //Version Merchant string `xml:"merchant" json:"merchant"` //Merchant number Encrypt string `xml:"encrypt" json:"encrypt"` //Encrypted data} const version = "V2.0" // JD Payment Versionconst merchantId = "22294531" const desKey = "ta4E/aspLA3lgFGKmNDNRYU92RkZ4w2t" const timeLayout = "20060102150405" const cny = "CNY" const practicalityGoodsType = "GT01" //Product type-Practical itemconst businessServiceConsumeCode = "100001" const practicality = "0" //Product type-Practical itemtype GoodsInfo struct { Id string `json:"id"` //Product number Name string `json:"name"` //Product name Price int64 `json:"price"` //Unit price of goods, unit segment Num uint32 `json:"num"` //Product quantity Type string `json:"type"` //Product Type} type ReceiverInfo struct { Name string `json:"name"` Address string `json:"address"` Mobile string `json:"mobile"` Province string `json:"province"` City string `json:"city"` Country string `json:"country"` } type KjInfo struct { GoodsSubmittedCustoms string `json:"goodsSubmittedCustoms"` // Whether to declare customs Y/N GoodsUnderBonded string `json:"goodsUnderBonded"` // Whether to pay under bonded goods Y/N} const jdPayUrl = "/jdpay/saveOrder" // pc h5 form form submission paymentfunc postFormPay(arg Order) (payStr string, err error) { // Payment parameters paramMap := make(map[string]string) amountStr := ("%.f", *100) totalFee, err := (amountStr, 10, 64) if err != nil { return payStr, err } var goodsInfos []GoodsInfo for _, v := range { priceStr := ("%.f", *100) price, err := (priceStr, 10, 64) if err != nil { return payStr, err } goodsInfos = append(goodsInfos, GoodsInfo{ Id: , Name: , Price: price, Num: , Type: practicalityGoodsType, // Product Type - Real Item }) } goodsInfoBytes, _ := (goodsInfos) kjInfo := KjInfo{GoodsSubmittedCustoms: "N", GoodsUnderBonded: "N"} kjInfoBytes, _ := (kjInfo) detailAddress := + + + receiverInfo := ReceiverInfo{ Name: , // Name of the consignee Mobile: , // Consignee's mobile phone number Address: detailAddress, // The address requires that it passes through provinces, cities and districts Province: , // Province City: , // city Country: , // district } receiverInfoBytes, _ := (receiverInfo) orderId := ("test%s%s", ().Format("20060102150405"), randNumber()) paramMap["version"] = version paramMap["merchant"] = merchantId paramMap["tradeNum"] = orderId // Order number paramMap["tradeName"] = orderId // Order description paramMap["tradeDesc"] = orderId // Order description paramMap["payMerchant"] = "test" // Merchant name paramMap["tradeTime"] = ().Format(timeLayout) paramMap["amount"] = ("%v", totalFee) paramMap["orderType"] = practicality paramMap["currency"] = cny paramMap["userId"] = "100" paramMap["expireTime"] = "3600" //Order expiration time, unit seconds paramMap["goodsInfo"] = string(goodsInfoBytes) paramMap["settleCurrency"] = cny paramMap["kjInfo"] = string(kjInfoBytes) paramMap["bizTp"] = businessServiceConsumeCode paramMap["notifyUrl"] = "/notify" paramMap["callbackUrl"] = "/verify" paramMap["receiverInfo"] = string(receiverInfoBytes) // Certificate privateKey, err := getKey("private_key") if err != nil { return payStr, err } // sign paramMap["sign"], err = getPaySign(paramMap, privateKey) if err != nil { return payStr, err } // Data encryption paramMap, err = encrypt3DES(paramMap, desKey) if err != nil { return payStr, err } // Splice payment form payStr = "<form action='" + jdPayUrl + "' method='post' id='pay_form'>" for k, v := range paramMap { payStr += "<input value='" + v + "' name='" + k + "' type='hidden'/>" } payStr += "</form>" payStr += "<script>var form = ('pay_form');()</script>" return payStr, nil }
3. Asynchronous notification
Data decryption, signature verification
// Decrypt asynchronous notification informationtype NotifyQuery struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` // Version number Merchant string `xml:"merchant" json:"merchant"` // Merchant number Result NotifyResult `xml:"result" json:"result"` // Transaction results Encrypt string `xml:"encrypt" json:"encrypt"` // Encrypted information} type NotifyDecrypt struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` // Version number Merchant string `xml:"merchant" json:"merchant"` // Merchant number Result NotifyResult `xml:"result" json:"result"` // Transaction results TradeNum string `xml:"tradeNum" json:"tradeNum"` // Order number TradeType int `xml:"tradeType" json:"tradeType"` // Transaction type Sign string `xml:"sign" json:"sign"` // Data signature Amount int64 `xml:"amount" json:"amount"` // Total amount of RMB payment OrderId string `json:"order_id"` // JD.com transaction flow number Status string `xml:"status" json:"status"` // Transaction status PayList NotifyPayList `xml:"payList" json:"payList"` // Payment method details} type NotifyResult struct { Code string `xml:"code" json:"code"` // Transaction return code Desc string `xml:"desc" json:"desc"` // Return code information} type NotifyPayList struct { Pay []NotifyPay `xml:"pay" json:"pay"` } type NotifyPay struct { PayType int `xml:"payType" json:"payType"` // Payment method Amount int64 `xml:"amount" json:"amount"` // Transaction amount Currency string `xml:"currency" json:"currency"` // Trading currency TradeTime string `xml:"tradeTime" json:"tradeTime"` // Trading time} // Decrypt asynchronous notification informationfunc notifyDataDecrypt(rawPost string) (notifyDecrypt NotifyDecrypt, err error) { // Analyze the encrypted payment institution parameters as structure var notifyQuery NotifyQuery err = ([]byte(rawPost), &notifyQuery) if err != nil { return notifyDecrypt, err } // Decrypt the payment institution parameters decryptBytes, err := decryptArg(notifyQuery, desKey) if err != nil { return notifyDecrypt, err } // The parameters of the decrypted payment institution are structured err = (decryptBytes, &notifyDecrypt) if err != nil { return notifyDecrypt, err } // Certificate publicKey, err := getKey("public_key") if err != nil { return notifyDecrypt, err } // Verify signature if !checkSign(decryptBytes, , publicKey) { return notifyDecrypt, err } return notifyDecrypt, nil }
4. Transaction inquiry
Inquiry of orders
type SearchWithoutSignRequest struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` // Version Merchant string `xml:"merchant" json:"merchant"` // Merchant number TradeNum string `xml:"tradeNum" json:"tradeNum"` // Order number OTradeNum string `xml:"oTradeNum" json:"oTradeNum"` // Original transaction number TradeType string `xml:"tradeType" json:"tradeType"` // Transaction type} type SearchWithSignRequest struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` // Version Merchant string `xml:"merchant" json:"merchant"` // Merchant number TradeNum string `xml:"tradeNum" json:"tradeNum"` // Order number OTradeNum string `xml:"oTradeNum" json:"oTradeNum"` // Original transaction number TradeType string `xml:"tradeType" json:"tradeType"` // Transaction type Sign string `xml:"sign" json:"sign"` // sign} type SearchResult struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` // Version number Merchant string `xml:"merchant" json:"merchant"` // Merchant number Result SearchResultRsp `xml:"result" json:"result"` // Transaction results Encrypt string `xml:"encrypt" json:"encrypt"` // Encrypted information} type SearchResultRsp struct { Code string `xml:"code" json:"code"` // Transaction return code Desc string `xml:"desc" json:"desc"` // Return code information} type SearchDecryptRsp struct { XMLName `xml:"jdpay" json:"-"` Merchant string `xml:"merchant" json:"merchant"` // Merchant number TradeNum string `xml:"tradeNum" json:"tradeNum"` // Order number TradeType string `xml:"tradeType" json:"tradeType"` // Transaction type Result SearchResultRsp `xml:"result" json:"result"` // Transaction results Sign string `xml:"sign" json:"sign"` // Data signature Amount int64 `xml:"amount" json:"amount"` // Total amount of RMB payment Status string `xml:"status" json:"status"` // Transaction status PayList SearchPayListRsp `xml:"payList" json:"payList"` // Payment method details} type SearchPayListRsp struct { Pay []SearchPayRsp `xml:"pay" json:"pay"` } type SearchPayRsp struct { PayType int `xml:"payType" json:"payType"` // Payment method Amount int64 `xml:"amount" json:"amount"` // Transaction amount Currency string `xml:"currency" json:"currency"` // Trading currency TradeTime string `xml:"tradeTime" json:"tradeTime"` // Trading time} const tradeWayUrl = "/service/query" const customTradeType = "0" // Transaction typeconst successCode = "000000" func searchTrade(orderId string) (searchDecryptRsp SearchDecryptRsp, err error) { searchWithoutSignRequest := SearchWithoutSignRequest{ Version: version, Merchant: merchantId, TradeNum: orderId, OTradeNum: "", TradeType: customTradeType, } xmlBytes, err := (searchWithoutSignRequest) xmlStr := + string(xmlBytes) xmlStr = replaceXmlStrBlankChar(xmlStr) // Certificate privateKey, err := getKey("private_key") if err != nil { return searchDecryptRsp, err } // sign sign, err := getRsaSign(xmlStr, privateKey) if err != nil { return searchDecryptRsp, err } searchWithSignRequest := SearchWithSignRequest{ Version: , Merchant: , TradeNum: , OTradeNum: , TradeType: , Sign: sign, } xmlBytes, err = (searchWithSignRequest) xmlStr = (, "\n") + string(xmlBytes) desKeyBytes, err := (desKey) if err != nil { return searchDecryptRsp, err } encryptBytes, err := tripleEcbDesEncrypt([]byte(xmlStr), desKeyBytes) if err != nil { return searchDecryptRsp, err } reqEncrypt := decimalByteSlice2HexString(encryptBytes) reqEncrypt = ([]byte(reqEncrypt)) searchWithEncrypt := ReqWithEncrypt{ Version: version, Merchant: merchantId, Encrypt: reqEncrypt, } xmlBytes, err = (searchWithEncrypt) if err != nil { return searchDecryptRsp, err } xmlStr = (, "\n") + string(xmlBytes) request, err := (, tradeWayUrl, (xmlStr)) if err != nil { return searchDecryptRsp, err } ("content-type", "application/xml; charset=utf-8") client := response, err := (request) if err != nil { return searchDecryptRsp, err } defer () bodyBytes, err := () if err != nil { return searchDecryptRsp, err } searchResult := new(SearchResult) if err = (bodyBytes, searchResult); err != nil { return searchDecryptRsp, err } if != successCode { return searchDecryptRsp, () } // Decrypt the data rspEncryptBytes, err := () rspEncryptBytes, err = hexString2Bytes(string(rspEncryptBytes)) if err != nil { return searchDecryptRsp, err } rspDecryptBytes, err := tripleEcbDesDecrypt(rspEncryptBytes, desKeyBytes) if err != nil { return searchDecryptRsp, err } err = (rspDecryptBytes, &searchDecryptRsp) if err != nil { return searchDecryptRsp, err } // Certificate publicKey, err := getKey("public_key") if err != nil { return searchDecryptRsp, err } // Verify signature if !checkSign(rspDecryptBytes, , publicKey) { return searchDecryptRsp, err } return searchDecryptRsp, nil }
5. Apply for a refund
Apply for a refund
// Refundtype Refund struct { Merchant string `json:"merchant"` TradeNum string `json:"tradeNum"` OTradeNum string `json:"oTradeNum"` Amount uint64 `json:"amount"` Currency string `json:"currency"` DesKey string `json:"desKey"` PublicKey string `json:"publicKey"` PrivateKey string `json:"privateKey"` } type RefundReqWithoutSign struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` Merchant string `xml:"merchant" json:"merchant"` TradeNum string `xml:"tradeNum" json:"tradeNum"` OTradeNum string `xml:"oTradeNum" json:"oTradeNum"` Amount uint64 `xml:"amount" json:"amount"` Currency string `xml:"currency" json:"currency"` } type RefundReqWithSign struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` Merchant string `xml:"merchant" json:"merchant"` TradeNum string `xml:"tradeNum" json:"tradeNum"` OTradeNum string `xml:"oTradeNum" json:"oTradeNum"` Amount uint64 `xml:"amount" json:"amount"` Currency string `xml:"currency" json:"currency"` Sign string `xml:"sign" json:"sign"` } type RefundResult struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` // Version number Merchant string `xml:"merchant" json:"merchant"` // Merchant number Result RefundPayResultRsp `xml:"result" json:"result"` // Refund results Encrypt string `xml:"encrypt" json:"encrypt"` // Encrypted information} type RefundPayResultRsp struct { Code string `xml:"code" json:"code"` // Transaction return code Desc string `xml:"desc" json:"desc"` // Return code information} type RefundPayDecryptRsp struct { XMLName `xml:"jdpay" json:"-"` Version string `xml:"version" json:"version"` // Version number Merchant string `xml:"merchant" json:"merchant"` // Merchant number TradeNum string `xml:"tradeNum" json:"tradeNum"` TradeType string `xml:"tradeType"json:"tradeType"` Result RefundPayResultRsp `xml:"result" json:"result"` // Refund results Sign string `xml:"sign" json:"sign"` Amount uint64 `xml:"amount" json:"amount"` Currency string `xml:"currency" json:"currency"` TradeTime string `xml:"tradeTime" json:"tradeTime"` Status string `xml:"status" json:"status"` } const refundGatewayUrl = "/service/refund" // Apply for a refundfunc refundTrade(orderId string, amount float64) (refundPayDecryptRsp RefundPayDecryptRsp, err error) { totalFee, err := (("%.f", amount*100), 10, 64) if err != nil { return refundPayDecryptRsp, err } refundReqWithoutSign := RefundReqWithoutSign{ Version: version, Merchant: merchantId, TradeNum: orderId + "-1", OTradeNum: orderId, Amount: totalFee, Currency: cny, } xmlBytes, err := (refundReqWithoutSign) xmlStr := + string(xmlBytes) xmlStr = replaceXmlStrBlankChar(xmlStr) // Certificate privateKey, err := getKey("private_key") if err != nil { return refundPayDecryptRsp, err } // sign sign, err := getRsaSign(xmlStr, privateKey) if err != nil { return refundPayDecryptRsp, err } refundReqWithSign := RefundReqWithSign{ Version: , Merchant: , TradeNum: , OTradeNum: , Amount: , Currency: , Sign: sign, } xmlBytes, err = (refundReqWithSign) xmlStr = (, "\n") + string(xmlBytes) desKeyBytes, err := (desKey) if err != nil { return refundPayDecryptRsp, err } encryptBytes, err := tripleEcbDesEncrypt([]byte(xmlStr), desKeyBytes) if err != nil { return refundPayDecryptRsp, err } reqEncrypt := decimalByteSlice2HexString(encryptBytes) reqEncrypt = ([]byte(reqEncrypt)) refundReqWithEncrypt := ReqWithEncrypt{ Version: version, Merchant: merchantId, Encrypt: reqEncrypt, } xmlBytes, err = (refundReqWithEncrypt) xmlStr = (, "\n") + string(xmlBytes) request, err := (, refundGatewayUrl, (xmlStr)) if err != nil { return refundPayDecryptRsp, err } ("content-type", "application/xml; charset=utf-8") client := response, err := (request) if err != nil { return refundPayDecryptRsp, err } defer () bodyBytes, err := () if err != nil { return refundPayDecryptRsp, err } refundResult := new(RefundResult) if err = (bodyBytes, refundResult); err != nil { return refundPayDecryptRsp, err } // Decrypt the data rspEncryptBytes, err := () if err != nil { return refundPayDecryptRsp, err } rspEncryptBytes, err = hexString2Bytes(string(rspEncryptBytes)) if err != nil { return refundPayDecryptRsp, err } rspDecryptBytes, err := tripleEcbDesDecrypt(rspEncryptBytes, desKeyBytes) if err != nil { return refundPayDecryptRsp, err } err = (rspDecryptBytes, &refundPayDecryptRsp) if err != nil { return refundPayDecryptRsp, err } // Certificate publicKey, err := getKey("public_key") if err != nil { return refundPayDecryptRsp, err } // Verify signature if !checkSign(rspDecryptBytes, , publicKey) { return refundPayDecryptRsp, err } return refundPayDecryptRsp, nil }
This is the article about golang implementing the JD Payment v2 version. For more related content on golang, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!