golang实现京东支付v2版本的示例代码
一、准备阶段
pc&h5接入步骤
官方文档https://payapi.jd.com/docList...
查看主要接入步骤
密钥生成
•需要设置desckey
•md5key和appidapp对接会使用
•证书文件名称
my_rsa_private_pkcs8_key.pem wy_rsa_public_key.pem
示例程序使用私钥格式为pkcs8格式
官方的SDK中的数据可以在示例程序中使用
下载SDK地址https://payapi.jd.com/docList...
找到接口文档中的Demo
还会用到的包
import( "encoding/base64" "encoding/json" "encoding/xml" "errors" "fmt" "io/ioutil" "net/http" "os" "strconv" "strings" "time" )
加密、解密、验证签名
packagemain
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"
)
funcrandNumber()string{
returnfmt.Sprintf("%05v",rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(100000))
}
funccheckSign(decryptBytes[]byte,sign,publicKeystring)bool{
decrypt:=string(decryptBytes)
clipStartIndex:=strings.Index(decrypt,"")
clipEndIndex:=strings.Index(decrypt," ")
xmlStart:=decrypt[0:clipStartIndex]
xmlEnd:=decrypt[clipEndIndex+7:len(decrypt)]
originXml:=xmlStart+xmlEnd
//签名校验
ifsign==""{
returnfalse
}
returncheckRsaSign(originXml,publicKey,sign)
}
funcreplaceXmlStrBlankChar(strstring)string{
str=strings.Replace(str,"\r","",-1)
str=strings.Replace(str,"\n","",-1)
str=strings.Replace(str,"\t","",-1)
reg,_:=regexp.Compile(">\\s+<")
str=reg.ReplaceAllString(str,"><")
reg,_=regexp.Compile("\\s+\\/>")
str=reg.ReplaceAllString(str,"/>")
returnstr
}
funcgetPaySign(paramMapmap[string]string,privateKeystring)(string,error){
payString:=getSortString(paramMap)
returngetRsaSign(payString,privateKey)
}
//------
//加密
funcencrypt3DES(paramMapmap[string]string,desKeystring)(map[string]string,error){
desKey=base64DecodeStr(desKey)
fork,v:=rangeparamMap{
ifk=="sign"||k=="merchant"||k=="version"{
continue
}
encrypt,err:=tripleEcbDesEncrypt([]byte(v),[]byte(desKey))
iferr!=nil{
returnparamMap,err
}
paramMap[k]=decimalByteSlice2HexString(encrypt)
}
returnparamMap,nil
}
funcdecryptArg(notifyQueryNotifyQuery,desKeystring)(decryptBytes[]byte,errerror){
desKeyBytes,err:=base64.StdEncoding.DecodeString(desKey)
iferr!=nil{
returnnil,err
}
encryptBytes,err:=base64.StdEncoding.DecodeString(notifyQuery.Encrypt)
iferr!=nil{
returnnil,err
}
encryptBytes,err=hexString2Bytes(string(encryptBytes))
iferr!=nil{
returnnil,err
}
decryptBytes,err=tripleEcbDesDecrypt(encryptBytes,desKeyBytes)
iferr!=nil{
returnnil,err
}
returndecryptBytes,nil
}
//JDAPP填充规则
funcjdPadding(origData[]byte)[]byte{
merchantData:=len(origData)
x:=(merchantData+4)%8
y:=0
ifx==0{
y=0
}else{
y=8-x
}
sizeByte:=integerToBytes(merchantData)
varresultByte[]byte
//填充byte数据长度
fori:=0;i<4;i++{
resultByte=append(resultByte,sizeByte[i])
}
//填充原数据长度
forj:=0;j>24&0xff)
byt[1]=byte(val>>16&0xff)
byt[2]=byte(val>>8&0xff)
byt[3]=byte(val&0xff)
returnbyt
}
//byte转16进制字符串
funcdecimalByteSlice2HexString(DecimalSlice[]byte)string{
varsa=make([]string,0)
for_,v:=rangeDecimalSlice{
sa=append(sa,fmt.Sprintf("%02X",v))
}
ss:=strings.Join(sa,"")
returnss
}
//十六进制字符串转byte
funchexString2Bytes(strstring)([]byte,error){
Bys,err:=hex.DecodeString(str)
iferr!=nil{
returnnil,err
}
returnBys,nil
}
//base解码
funcbase64DecodeStr(srcstring)string{
a,err:=base64.StdEncoding.DecodeString(src)
iferr!=nil{
return""
}
returnstring(a)
}
//Des解密
funcdecrypt(crypted,key[]byte)([]byte,error){
iflen(crypted)<1||len(key)<1{
returnnil,errors.New("wrongdataorkey")
}
block,err:=des.NewCipher(key)
iferr!=nil{
returnnil,err
}
out:=make([]byte,len(crypted))
dst:=out
bs:=block.BlockSize()
iflen(crypted)%bs!=0{
returnnil,errors.New("wrongcryptedsize")
}
forlen(crypted)>0{
block.Decrypt(dst,crypted[:bs])
crypted=crypted[bs:]
dst=dst[bs:]
}
returnout,nil
}
//[golangECB3DESDecrypt]
functripleEcbDesDecrypt(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)
iferr!=nil{
returnnil,err
}
buf2,err:=encrypt(buf1,k2)
iferr!=nil{
returnnil,err
}
out,err:=decrypt(buf2,k1)
iferr!=nil{
returnnil,err
}
out=jdUnPadding(out)
returnout,nil
}
//sha256加密
funchasha256(strstring)string{
h:=sha256.New()
h.Write([]byte(str))
cipherStr:=h.Sum(nil)
//returncipherStr
returnhex.EncodeToString(cipherStr)
}
//base解编码
funcbase64EncodeStr(srcstring)string{
returnbase64.StdEncoding.EncodeToString([]byte(src))
}
//对消息的散列值进行数字签名
funcsignPKCS1v15(msg,privateKey[]byte,hashTypecrypto.Hash)([]byte,error){
block,_:=pem.Decode(privateKey)
ifblock==nil{
returnnil,errors.New("privatekeyformaterror")
}
pri,err:=x509.ParsePKCS8PrivateKey(block.Bytes)
iferr!=nil{
returnnil,errors.New("parseprivatekeyerror")
}
key,ok:=pri.(*rsa.PrivateKey)
ifok==false{
returnnil,errors.New("privatekeyformaterror")
}
sign,err:=rsa.SignPKCS1v15(cryptoRand.Reader,key,hashType,msg)
iferr!=nil{
returnnil,errors.New("signerror")
}
returnsign,nil
}
//Des加密
funcencrypt(origData,key[]byte)([]byte,error){
iflen(origData)<1||len(key)<1{
returnnil,errors.New("wrongdataorkey")
}
block,err:=des.NewCipher(key)
iferr!=nil{
returnnil,err
}
bs:=block.BlockSize()
iflen(origData)%bs!=0{
returnnil,errors.New("wrongpadding")
}
out:=make([]byte,len(origData))
dst:=out
forlen(origData)>0{
block.Encrypt(dst,origData[:bs])
origData=origData[bs:]
dst=dst[bs:]
}
returnout,nil
}
//[golangECB3DESEncrypt]
functripleEcbDesEncrypt(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)
iferr!=nil{
returnnil,err
}
buf2,err:=decrypt(buf1,k2)
iferr!=nil{
returnnil,err
}
out,err:=encrypt(buf2,k3)
iferr!=nil{
returnnil,err
}
returnout,nil
}
//------------
//验证签名
funcverifyPKCS1v15(msg,sign,publicKey[]byte,hashTypecrypto.Hash)bool{
block,_:=pem.Decode(publicKey)
ifblock==nil{
returnfalse
}
pub,err:=x509.ParsePKIXPublicKey(block.Bytes)
iferr!=nil{
panic(err)
}
err=rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey),hashType,msg,sign)
returnerr==nil
}
funcgetRsaSign(paramStrstring,privateKeystring)(string,error){
sha256Str:=hasha256(paramStr)
sign,err:=signPKCS1v15([]byte(sha256Str),[]byte(privateKey),crypto.Hash(0))
iferr!=nil{
return"",err
}
base64String:=base64.StdEncoding.EncodeToString(sign)
returnbase64String,nil
}
funccheckRsaSign(paramStrstring,publicKey,signstring)bool{
signByte,err:=base64.StdEncoding.DecodeString(sign)
iferr!=nil{
returnfalse
}
sha256Str:=hasha256(paramStr)
returnverifyPKCS1v15([]byte(sha256Str),signByte,[]byte(publicKey),crypto.Hash(0))
}
//-------
//字符串拼接
//支付字符串拼接
funcgetSortString(mmap[string]string)string{
varbufbytes.Buffer
keys:=make([]string,0,len(m))
fork:=rangem{
keys=append(keys,k)
}
sort.Strings(keys)
for_,k:=rangekeys{
vs:=m[k]
ifbuf.Len()>0{
buf.WriteByte('&')
}
buf.WriteString(k)
buf.WriteByte('=')
buf.WriteString(vs)
}
returnbuf.String()
}
程序中加载密钥
funcgetKey(keyTypestring)(string,error){
keyMap:=map[string]string{
"private_key":"./private.pem",
"public_key":"./public.pem",
}
path,ok:=keyMap[keyType]
if!ok{
return"",errors.New("keypathnotexists")
}
fileHandler,err:=os.Open(path)
iferr!=nil{
return"",err
}
deferfileHandler.Close()
keyBytes,err:=ioutil.ReadAll(fileHandler)
iferr!=nil{
return"",err
}
returnstring(keyBytes),nil
}
二、发起支付
常量
常量 constversion="V2.0"//京东支付版本 constmerchantId=""//商户id constdesKey=""//desckey consttimeLayout="20060102150405" constcny="CNY" constpracticalityGoodsType="GT01"//商品类型-实物 constbusinessServiceConsumeCode="100001" constpracticality="0"//商品类型-实物
调用在线支付接口
pch5发起支付
官方文档https://payapi.jd.com/docList...
typeOrderstruct{
OrderIdstring`json:"order_id"`
Amountfloat64`json:"amount"`
Items[]*OrderItem`json:"items"`
ShippingAddress*OrderShippingAddress`json:"shipping_address"`
}
typeOrderItemstruct{
GoodsNostring`json:"goods_no"`
GoodsNamestring`json:"goods_name"`
GoodsPricefloat64`json:"goods_price"`
GoodsNumuint32`json:"goods_num"`
}
typeOrderShippingAddressstruct{
Namestring`json:"name"`
Mobilestring`json:"mobile"`
Addressstring`json:"address"`
Provincestring`json:"province"`
Citystring`json:"city"`
Countrystring`json:"country"`
}
typeReqWithEncryptstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本
Merchantstring`xml:"merchant"json:"merchant"`//商户号
Encryptstring`xml:"encrypt"json:"encrypt"`//加密数据
}
constversion="V2.0"//京东支付版本
constmerchantId="22294531"
constdesKey="ta4E/aspLA3lgFGKmNDNRYU92RkZ4w2t"
consttimeLayout="20060102150405"
constcny="CNY"
constpracticalityGoodsType="GT01"//商品类型-实物
constbusinessServiceConsumeCode="100001"
constpracticality="0"//商品类型-实物
typeGoodsInfostruct{
Idstring`json:"id"`//商品编号
Namestring`json:"name"`//商品名称
Priceint64`json:"price"`//商品单价,单位分
Numuint32`json:"num"`//商品数量
Typestring`json:"type"`//商品类型
}
typeReceiverInfostruct{
Namestring`json:"name"`
Addressstring`json:"address"`
Mobilestring`json:"mobile"`
Provincestring`json:"province"`
Citystring`json:"city"`
Countrystring`json:"country"`
}
typeKjInfostruct{
GoodsSubmittedCustomsstring`json:"goodsSubmittedCustoms"`//是否报关Y/N
GoodsUnderBondedstring`json:"goodsUnderBonded"`//是否保税货物项下付款Y/N
}
constjdPayUrl="https://wepay.jd.com/jdpay/saveOrder"
//pch5form表单提交支付
funcpostFormPay(argOrder)(payStrstring,errerror){
//支付参数
paramMap:=make(map[string]string)
amountStr:=fmt.Sprintf("%.f",arg.Amount*100)
totalFee,err:=strconv.ParseInt(amountStr,10,64)
iferr!=nil{
returnpayStr,err
}
vargoodsInfos[]GoodsInfo
for_,v:=rangearg.Items{
priceStr:=fmt.Sprintf("%.f",v.GoodsPrice*100)
price,err:=strconv.ParseInt(priceStr,10,64)
iferr!=nil{
returnpayStr,err
}
goodsInfos=append(goodsInfos,GoodsInfo{
Id:v.GoodsNo,
Name:v.GoodsName,
Price:price,
Num:v.GoodsNum,
Type:practicalityGoodsType,//商品类型-实物
})
}
goodsInfoBytes,_:=json.Marshal(goodsInfos)
kjInfo:=KjInfo{GoodsSubmittedCustoms:"N",GoodsUnderBonded:"N"}
kjInfoBytes,_:=json.Marshal(kjInfo)
detailAddress:=arg.ShippingAddress.Province+arg.ShippingAddress.City+arg.ShippingAddress.Country+arg.ShippingAddress.Address
receiverInfo:=ReceiverInfo{
Name:arg.ShippingAddress.Name,//收货人姓名
Mobile:arg.ShippingAddress.Mobile,//收货人手机号
Address:detailAddress,//地址要求包过省市区
Province:arg.ShippingAddress.Province,//省
City:arg.ShippingAddress.City,//市
Country:arg.ShippingAddress.Country,//区
}
receiverInfoBytes,_:=json.Marshal(receiverInfo)
orderId:=fmt.Sprintf("test%s%s",time.Now().Format("20060102150405"),randNumber())
paramMap["version"]=version
paramMap["merchant"]=merchantId
paramMap["tradeNum"]=orderId//订单号
paramMap["tradeName"]=orderId//订单描述
paramMap["tradeDesc"]=orderId//订单描述
paramMap["payMerchant"]="test"//商户名称
paramMap["tradeTime"]=time.Now().Format(timeLayout)
paramMap["amount"]=fmt.Sprintf("%v",totalFee)
paramMap["orderType"]=practicality
paramMap["currency"]=cny
paramMap["userId"]="100"
paramMap["expireTime"]="3600"//订单失效时长,单位秒
paramMap["goodsInfo"]=string(goodsInfoBytes)
paramMap["settleCurrency"]=cny
paramMap["kjInfo"]=string(kjInfoBytes)
paramMap["bizTp"]=businessServiceConsumeCode
paramMap["notifyUrl"]="http://tools.localhost/notify"
paramMap["callbackUrl"]="http://tools.localhost/verify"
paramMap["receiverInfo"]=string(receiverInfoBytes)
//证书
privateKey,err:=getKey("private_key")
iferr!=nil{
returnpayStr,err
}
//签名
paramMap["sign"],err=getPaySign(paramMap,privateKey)
iferr!=nil{
returnpayStr,err
}
//数据加密
paramMap,err=encrypt3DES(paramMap,desKey)
iferr!=nil{
returnpayStr,err
}
//拼接支付表单
payStr=""
fork,v:=rangeparamMap{
payStr+=" "
}
payStr+=""
payStr+=""
returnpayStr,nil
}
三、异步通知
数据解密、签名校验
//异步通知信息解密
typeNotifyQuerystruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本号
Merchantstring`xml:"merchant"json:"merchant"`//商户号
ResultNotifyResult`xml:"result"json:"result"`//交易结果
Encryptstring`xml:"encrypt"json:"encrypt"`//加密信息
}
typeNotifyDecryptstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本号
Merchantstring`xml:"merchant"json:"merchant"`//商户号
ResultNotifyResult`xml:"result"json:"result"`//交易结果
TradeNumstring`xml:"tradeNum"json:"tradeNum"`//订单号
TradeTypeint`xml:"tradeType"json:"tradeType"`//交易类型
Signstring`xml:"sign"json:"sign"`//数据签名
Amountint64`xml:"amount"json:"amount"`//人民币支付总金额
OrderIdstring`json:"order_id"`//京东交易流水号
Statusstring`xml:"status"json:"status"`//交易状态
PayListNotifyPayList`xml:"payList"json:"payList"`//支付方式明细
}
typeNotifyResultstruct{
Codestring`xml:"code"json:"code"`//交易返回码
Descstring`xml:"desc"json:"desc"`//返回码信息
}
typeNotifyPayListstruct{
Pay[]NotifyPay`xml:"pay"json:"pay"`
}
typeNotifyPaystruct{
PayTypeint`xml:"payType"json:"payType"`//支付方式
Amountint64`xml:"amount"json:"amount"`//交易金额
Currencystring`xml:"currency"json:"currency"`//交易币种
TradeTimestring`xml:"tradeTime"json:"tradeTime"`//交易时间
}
//异步通知信息解密
funcnotifyDataDecrypt(rawPoststring)(notifyDecryptNotifyDecrypt,errerror){
//解析加密的支付机构参数为结构体
varnotifyQueryNotifyQuery
err=xml.Unmarshal([]byte(rawPost),¬ifyQuery)
iferr!=nil{
returnnotifyDecrypt,err
}
//解密支付机构参数
decryptBytes,err:=decryptArg(notifyQuery,desKey)
iferr!=nil{
returnnotifyDecrypt,err
}
//解析解密后的支付机构参数为结构体
err=xml.Unmarshal(decryptBytes,¬ifyDecrypt)
iferr!=nil{
returnnotifyDecrypt,err
}
//证书
publicKey,err:=getKey("public_key")
iferr!=nil{
returnnotifyDecrypt,err
}
//校验签名
if!checkSign(decryptBytes,notifyDecrypt.Sign,publicKey){
returnnotifyDecrypt,err
}
returnnotifyDecrypt,nil
}
四、交易查询
查询订单
typeSearchWithoutSignRequeststruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本
Merchantstring`xml:"merchant"json:"merchant"`//商户号
TradeNumstring`xml:"tradeNum"json:"tradeNum"`//订单编号
OTradeNumstring`xml:"oTradeNum"json:"oTradeNum"`//原交易流水号
TradeTypestring`xml:"tradeType"json:"tradeType"`//交易类型
}
typeSearchWithSignRequeststruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本
Merchantstring`xml:"merchant"json:"merchant"`//商户号
TradeNumstring`xml:"tradeNum"json:"tradeNum"`//订单编号
OTradeNumstring`xml:"oTradeNum"json:"oTradeNum"`//原交易流水号
TradeTypestring`xml:"tradeType"json:"tradeType"`//交易类型
Signstring`xml:"sign"json:"sign"`//签名
}
typeSearchResultstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本号
Merchantstring`xml:"merchant"json:"merchant"`//商户号
ResultSearchResultRsp`xml:"result"json:"result"`//交易结果
Encryptstring`xml:"encrypt"json:"encrypt"`//加密信息
}
typeSearchResultRspstruct{
Codestring`xml:"code"json:"code"`//交易返回码
Descstring`xml:"desc"json:"desc"`//返回码信息
}
typeSearchDecryptRspstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Merchantstring`xml:"merchant"json:"merchant"`//商户号
TradeNumstring`xml:"tradeNum"json:"tradeNum"`//订单编号
TradeTypestring`xml:"tradeType"json:"tradeType"`//交易类型
ResultSearchResultRsp`xml:"result"json:"result"`//交易结果
Signstring`xml:"sign"json:"sign"`//数据签名
Amountint64`xml:"amount"json:"amount"`//人民币支付总金额
Statusstring`xml:"status"json:"status"`//交易状态
PayListSearchPayListRsp`xml:"payList"json:"payList"`//支付方式明细
}
typeSearchPayListRspstruct{
Pay[]SearchPayRsp`xml:"pay"json:"pay"`
}
typeSearchPayRspstruct{
PayTypeint`xml:"payType"json:"payType"`//支付方式
Amountint64`xml:"amount"json:"amount"`//交易金额
Currencystring`xml:"currency"json:"currency"`//交易币种
TradeTimestring`xml:"tradeTime"json:"tradeTime"`//交易时间
}
consttradeWayUrl="https://paygate.jd.com/service/query"
constcustomTradeType="0"//交易类型
constsuccessCode="000000"
funcsearchTrade(orderIdstring)(searchDecryptRspSearchDecryptRsp,errerror){
searchWithoutSignRequest:=SearchWithoutSignRequest{
Version:version,
Merchant:merchantId,
TradeNum:orderId,
OTradeNum:"",
TradeType:customTradeType,
}
xmlBytes,err:=xml.Marshal(searchWithoutSignRequest)
xmlStr:=xml.Header+string(xmlBytes)
xmlStr=replaceXmlStrBlankChar(xmlStr)
//证书
privateKey,err:=getKey("private_key")
iferr!=nil{
returnsearchDecryptRsp,err
}
//签名
sign,err:=getRsaSign(xmlStr,privateKey)
iferr!=nil{
returnsearchDecryptRsp,err
}
searchWithSignRequest:=SearchWithSignRequest{
Version:searchWithoutSignRequest.Version,
Merchant:searchWithoutSignRequest.Merchant,
TradeNum:searchWithoutSignRequest.TradeNum,
OTradeNum:searchWithoutSignRequest.OTradeNum,
TradeType:searchWithoutSignRequest.TradeType,
Sign:sign,
}
xmlBytes,err=xml.Marshal(searchWithSignRequest)
xmlStr=strings.TrimRight(xml.Header,"\n")+string(xmlBytes)
desKeyBytes,err:=base64.StdEncoding.DecodeString(desKey)
iferr!=nil{
returnsearchDecryptRsp,err
}
encryptBytes,err:=tripleEcbDesEncrypt([]byte(xmlStr),desKeyBytes)
iferr!=nil{
returnsearchDecryptRsp,err
}
reqEncrypt:=decimalByteSlice2HexString(encryptBytes)
reqEncrypt=base64.StdEncoding.EncodeToString([]byte(reqEncrypt))
searchWithEncrypt:=ReqWithEncrypt{
Version:version,
Merchant:merchantId,
Encrypt:reqEncrypt,
}
xmlBytes,err=xml.Marshal(searchWithEncrypt)
iferr!=nil{
returnsearchDecryptRsp,err
}
xmlStr=strings.TrimRight(xml.Header,"\n")+string(xmlBytes)
request,err:=http.NewRequest(http.MethodPost,tradeWayUrl,strings.NewReader(xmlStr))
iferr!=nil{
returnsearchDecryptRsp,err
}
request.Header.Add("content-type","application/xml;charset=utf-8")
client:=http.DefaultClient
response,err:=client.Do(request)
iferr!=nil{
returnsearchDecryptRsp,err
}
deferresponse.Body.Close()
bodyBytes,err:=ioutil.ReadAll(response.Body)
iferr!=nil{
returnsearchDecryptRsp,err
}
searchResult:=new(SearchResult)
iferr=xml.Unmarshal(bodyBytes,searchResult);err!=nil{
returnsearchDecryptRsp,err
}
ifsearchResult.Result.Code!=successCode{
returnsearchDecryptRsp,errors.New(searchResult.Result.Desc)
}
//解密数据
rspEncryptBytes,err:=base64.StdEncoding.DecodeString(searchResult.Encrypt)
rspEncryptBytes,err=hexString2Bytes(string(rspEncryptBytes))
iferr!=nil{
returnsearchDecryptRsp,err
}
rspDecryptBytes,err:=tripleEcbDesDecrypt(rspEncryptBytes,desKeyBytes)
iferr!=nil{
returnsearchDecryptRsp,err
}
err=xml.Unmarshal(rspDecryptBytes,&searchDecryptRsp)
iferr!=nil{
returnsearchDecryptRsp,err
}
//证书
publicKey,err:=getKey("public_key")
iferr!=nil{
returnsearchDecryptRsp,err
}
//校验签名
if!checkSign(rspDecryptBytes,searchDecryptRsp.Sign,publicKey){
returnsearchDecryptRsp,err
}
returnsearchDecryptRsp,nil
}
五、申请退款
申请退款
//退款
typeRefundstruct{
Merchantstring`json:"merchant"`
TradeNumstring`json:"tradeNum"`
OTradeNumstring`json:"oTradeNum"`
Amountuint64`json:"amount"`
Currencystring`json:"currency"`
DesKeystring`json:"desKey"`
PublicKeystring`json:"publicKey"`
PrivateKeystring`json:"privateKey"`
}
typeRefundReqWithoutSignstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`
Merchantstring`xml:"merchant"json:"merchant"`
TradeNumstring`xml:"tradeNum"json:"tradeNum"`
OTradeNumstring`xml:"oTradeNum"json:"oTradeNum"`
Amountuint64`xml:"amount"json:"amount"`
Currencystring`xml:"currency"json:"currency"`
}
typeRefundReqWithSignstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`
Merchantstring`xml:"merchant"json:"merchant"`
TradeNumstring`xml:"tradeNum"json:"tradeNum"`
OTradeNumstring`xml:"oTradeNum"json:"oTradeNum"`
Amountuint64`xml:"amount"json:"amount"`
Currencystring`xml:"currency"json:"currency"`
Signstring`xml:"sign"json:"sign"`
}
typeRefundResultstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本号
Merchantstring`xml:"merchant"json:"merchant"`//商户号
ResultRefundPayResultRsp`xml:"result"json:"result"`//退款结果
Encryptstring`xml:"encrypt"json:"encrypt"`//加密信息
}
typeRefundPayResultRspstruct{
Codestring`xml:"code"json:"code"`//交易返回码
Descstring`xml:"desc"json:"desc"`//返回码信息
}
typeRefundPayDecryptRspstruct{
XMLNamexml.Name`xml:"jdpay"json:"-"`
Versionstring`xml:"version"json:"version"`//版本号
Merchantstring`xml:"merchant"json:"merchant"`//商户号
TradeNumstring`xml:"tradeNum"json:"tradeNum"`
TradeTypestring`xml:"tradeType"json:"tradeType"`
ResultRefundPayResultRsp`xml:"result"json:"result"`//退款结果
Signstring`xml:"sign"json:"sign"`
Amountuint64`xml:"amount"json:"amount"`
Currencystring`xml:"currency"json:"currency"`
TradeTimestring`xml:"tradeTime"json:"tradeTime"`
Statusstring`xml:"status"json:"status"`
}
constrefundGatewayUrl="https://paygate.jd.com/service/refund"
//申请退款
funcrefundTrade(orderIdstring,amountfloat64)(refundPayDecryptRspRefundPayDecryptRsp,errerror){
totalFee,err:=strconv.ParseUint(fmt.Sprintf("%.f",amount*100),10,64)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
refundReqWithoutSign:=RefundReqWithoutSign{
Version:version,
Merchant:merchantId,
TradeNum:orderId+"-1",
OTradeNum:orderId,
Amount:totalFee,
Currency:cny,
}
xmlBytes,err:=xml.Marshal(refundReqWithoutSign)
xmlStr:=xml.Header+string(xmlBytes)
xmlStr=replaceXmlStrBlankChar(xmlStr)
//证书
privateKey,err:=getKey("private_key")
iferr!=nil{
returnrefundPayDecryptRsp,err
}
//签名
sign,err:=getRsaSign(xmlStr,privateKey)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
refundReqWithSign:=RefundReqWithSign{
Version:refundReqWithoutSign.Version,
Merchant:refundReqWithoutSign.Merchant,
TradeNum:refundReqWithoutSign.TradeNum,
OTradeNum:refundReqWithoutSign.OTradeNum,
Amount:refundReqWithoutSign.Amount,
Currency:refundReqWithoutSign.Currency,
Sign:sign,
}
xmlBytes,err=xml.Marshal(refundReqWithSign)
xmlStr=strings.TrimRight(xml.Header,"\n")+string(xmlBytes)
desKeyBytes,err:=base64.StdEncoding.DecodeString(desKey)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
encryptBytes,err:=tripleEcbDesEncrypt([]byte(xmlStr),desKeyBytes)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
reqEncrypt:=decimalByteSlice2HexString(encryptBytes)
reqEncrypt=base64.StdEncoding.EncodeToString([]byte(reqEncrypt))
refundReqWithEncrypt:=ReqWithEncrypt{
Version:version,
Merchant:merchantId,
Encrypt:reqEncrypt,
}
xmlBytes,err=xml.Marshal(refundReqWithEncrypt)
xmlStr=strings.TrimRight(xml.Header,"\n")+string(xmlBytes)
request,err:=http.NewRequest(http.MethodPost,refundGatewayUrl,strings.NewReader(xmlStr))
iferr!=nil{
returnrefundPayDecryptRsp,err
}
request.Header.Add("content-type","application/xml;charset=utf-8")
client:=http.DefaultClient
response,err:=client.Do(request)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
deferresponse.Body.Close()
bodyBytes,err:=ioutil.ReadAll(response.Body)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
refundResult:=new(RefundResult)
iferr=xml.Unmarshal(bodyBytes,refundResult);err!=nil{
returnrefundPayDecryptRsp,err
}
//解密数据
rspEncryptBytes,err:=base64.StdEncoding.DecodeString(refundResult.Encrypt)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
rspEncryptBytes,err=hexString2Bytes(string(rspEncryptBytes))
iferr!=nil{
returnrefundPayDecryptRsp,err
}
rspDecryptBytes,err:=tripleEcbDesDecrypt(rspEncryptBytes,desKeyBytes)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
err=xml.Unmarshal(rspDecryptBytes,&refundPayDecryptRsp)
iferr!=nil{
returnrefundPayDecryptRsp,err
}
//证书
publicKey,err:=getKey("public_key")
iferr!=nil{
returnrefundPayDecryptRsp,err
}
//校验签名
if!checkSign(rspDecryptBytes,refundPayDecryptRsp.Sign,publicKey){
returnrefundPayDecryptRsp,err
}
returnrefundPayDecryptRsp,nil
}
到此这篇关于golang实现京东支付v2版本的文章就介绍到这了,更多相关go京东支付v2内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!