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内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!