返回顶部
首页 > 资讯 > 后端开发 > GO >使用golang怎么实现一个京东支付功能
  • 714
分享到

使用golang怎么实现一个京东支付功能

2023-06-06 16:06:43 714人浏览 泡泡鱼
摘要

这篇文章主要介绍了使用golang怎么实现一个京东支付功能,此处通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考价值,需要的朋友可以参考下:什么是Golanggolang 是Google开发的一种静态强类型、编译型、并发型

这篇文章主要介绍了使用golang怎么实现一个京东支付功能,此处通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考价值,需要的朋友可以参考下:

什么是Golang

golang 是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言,其语法与 C语言相近,但并不包括如枚举、异常处理、继承、泛型、断言、虚函数等功能。

一、准备阶段

密钥生成

• 需要设置desc key

• md5 key 和 app id app对接会使用

• 证书文件名称

my_rsa_private_pkcs8_key.pemwy_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")

加密、解密、验证签名

package mainimport (  "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 fmt.Sprintf("%05v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(100000))}func checkSign(decryptBytes []byte, sign, publicKey string) bool {  decrypt := string(decryptBytes)  clipStartIndex := strings.Index(decrypt, "<sign>")  clipEndIndex := strings.Index(decrypt, "</sign>")  xmlStart := decrypt[0:clipStartIndex]  xmlEnd := decrypt[clipEndIndex+7 : len(decrypt)]  originXml := xmlStart + xmlEnd  //签名校验  if sign == "" {    return false  }  return checkRsaSign(originXml, publicKey, sign)}func replaceXmlStrBlankChar(str string) 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, "/>")  return str}func getPaySign(paramMap map[string]string, privateKey string) (string, error) {  payString := getSortString(paramMap)  return getRsaSign(payString, privateKey)}// ------// 加密func 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 := base64.StdEncoding.DecodeString(desKey)  if err != nil {    return nil, err  }  encryptBytes, err := base64.StdEncoding.DecodeString(notifyQuery.Encrypt)  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填充规则func 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  //填充byte数据长度  for i := 0; i < 4; i++ {    resultByte = append(resultByte, sizeByte[i])  }  //填充原数据长度  for j := 0; j < merchantData; j++ {    resultByte = append(resultByte, origData[j])  }  //填充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}// 字节数组表示的实际长度func 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转16进制字符串func decimalByteSlice2HexString(DecimalSlice []byte) string {  var sa = make([]string, 0)  for _, v := range DecimalSlice {    sa = append(sa, fmt.Sprintf("%02X", v))  }  ss := strings.Join(sa, "")  return ss}// 十六进制字符串转bytefunc hexString2Bytes(str string) ([]byte, error) {  Bys, err := hex.DecodeString(str)  if err != nil {    return nil, err  }  return Bys, nil}// base解码func base64DecodeStr(src string) string {  a, err := base64.StdEncoding.DecodeString(src)  if err != nil {    return ""  }  return string(a)}// Des解密func decrypt(crypted, key []byte) ([]byte, error) {  if len(crypted) < 1 || len(key) < 1 {    return nil, errors.New("wrong data or key")  }  block, err := des.NewCipher(key)  if err != nil {    return nil, err  }  out := make([]byte, len(crypted))  dst := out  bs := block.BlockSize()  if len(crypted)%bs != 0 {    return nil, errors.New("wrong crypted size")  }  for len(crypted) > 0 {    block.Decrypt(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加密func hasha256(str string) string {  h := sha256.New()  h.Write([]byte(str))  cipherStr := h.Sum(nil)  //return cipherStr  return hex.EncodeToString(cipherStr)}// base解编码func base64EncodeStr(src string) string {  return base64.StdEncoding.EncodeToString([]byte(src))}// 对消息的散列值进行数字签名func signPKCS1v15(msg, privateKey []byte, hashType crypto.Hash) ([]byte, error) {  block, _ := pem.Decode(privateKey)  if block == nil {    return nil, errors.New("private key fORMat error")  }  pri, err := x509.ParsePKCS8PrivateKey(block.Bytes)  if err != nil {    return nil, errors.New("parse private key error")  }  key, ok := pri.(*rsa.PrivateKey)  if ok == false {    return nil, errors.New("private key format error")  }  sign, err := rsa.SignPKCS1v15(cryptoRand.Reader, key, hashType, msg)  if err != nil {    return nil, errors.New("sign error")  }  return sign, nil}// Des加密func encrypt(origData, key []byte) ([]byte, error) {  if len(origData) < 1 || len(key) < 1 {    return nil, errors.New("wrong data or key")  }  block, err := des.NewCipher(key)  if err != nil {    return nil, err  }  bs := block.BlockSize()  if len(origData)%bs != 0 {    return nil, errors.New("wrong padding")  }  out := make([]byte, len(origData))  dst := out  for len(origData) > 0 {    block.Encrypt(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}// ------------// 验证签名func verifyPKCS1v15(msg, sign, publicKey []byte, hashType crypto.Hash) bool {  block, _ := pem.Decode(publicKey)  if block == nil {    return false  }  pub, err := x509.ParsePKIXPublicKey(block.Bytes)  if err != nil {    panic(err)  }  err = rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), hashType, msg, sign)  return err == nil}func getRsaSign(paramStr string, privateKey string) (string, error) {  sha256Str := hasha256(paramStr)  sign, err := signPKCS1v15([]byte(sha256Str), []byte(privateKey), crypto.Hash(0))  if err != nil {    return "", err  }  base64String := base64.StdEncoding.EncodeToString(sign)  return base64String, nil}func checkRsaSign(paramStr string, publicKey, sign string) bool {  signByte, err := base64.StdEncoding.DecodeString(sign)  if err != nil {    return false  }  sha256Str := hasha256(paramStr)  return verifyPKCS1v15([]byte(sha256Str), signByte, []byte(publicKey), crypto.Hash(0))}// -------// 字符串拼接// 支付字符串拼接func getSortString(m map[string]string) string {  var buf bytes.Buffer  keys := make([]string, 0, len(m))  for k := range m {    keys = append(keys, k)  }  sort.Strings(keys)  for _, k := range keys {    vs := m[k]    if buf.Len() > 0 {      buf.WriteByte('&')    }    buf.WriteString(k)    buf.WriteByte('=')    buf.WriteString(vs)  }  return buf.String()}

程序中加载密钥

func getKey(keyType string) (string, error) {  keyMap := map[string]string{    "private_key": "./private.pem",    "public_key": "./public.pem",  }  path, ok := keyMap[keyType]  if !ok {    return "", errors.New("key path not exists")  }  fileHandler, err := os.Open(path)  if err != nil {    return "", err  }  defer fileHandler.Close()  keyBytes, err := ioutil.ReadAll(fileHandler)  if err != nil {    return "", err  }  return string(keyBytes), nil}

二、发起支付

常量

常量const version = "V2.0" // 京东支付版本const merchantId = "" // 商户idconst desKey = ""   // desc keyconst timeLayout = "20060102150405"const cny = "CNY"const practicalityGoodsType = "GT01" //商品类型-实物const businessServiceConsumeCode = "100001"const practicality = "0" //商品类型-实物

调用在线支付接口

pc h6 发起支付

官方文档 https://payapi.jd.com/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.Name `xml:"jdpay" json:"-"`  Version string  `xml:"version" json:"version"`  //版本  Merchant string  `xml:"merchant" json:"merchant"` //商户号  Encrypt string  `xml:"encrypt" json:"encrypt"`  //加密数据}const version = "V2.0" // 京东支付版本const merchantId = "22294531"const desKey = "ta4E/aspLA3lgFGKmNDNRYU92RkZ4w2t"const timeLayout = "20060102150405"const cny = "CNY"const practicalityGoodsType = "GT01" //商品类型-实物const businessServiceConsumeCode = "100001"const practicality = "0" //商品类型-实物type GoodsInfo struct {  Id  string `json:"id"`  //商品编号  Name string `json:"name"` //商品名称  Price int64 `json:"price"` //商品单价,单位分  Num  uint32 `json:"num"`  //商品数量  Type string `json:"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"` // 是否报关Y/N  GoodsUnderBonded   string `json:"goodsUnderBonded"`   // 是否保税货物项下付款Y/N}const jdPayUrl = "https://wepay.jd.com/jdpay/saveOrder"// pc h6 form 表单提交支付func postFormPay(arg Order) (payStr string, err error) {  // 支付参数  paramMap := make(map[string]string)  amountStr := fmt.Sprintf("%.f", arg.Amount*100)  totalFee, err := strconv.ParseInt(amountStr, 10, 64)  if err != nil {    return payStr, err  }  var goodsInfos []GoodsInfo  for _, v := range arg.Items {    priceStr := fmt.Sprintf("%.f", v.GoodsPrice*100)    price, err := strconv.ParseInt(priceStr, 10, 64)    if err != nil {      return payStr, 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")  if err != nil {    return payStr, err  }  // 签名  paramMap["sign"], err = getPaySign(paramMap, privateKey)  if err != nil {    return payStr, err  }  // 数据加密  paramMap, err = encrypt3DES(paramMap, desKey)  if err != nil {    return payStr, err  }  // 拼接支付表单  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 = document.getElementById('pay_form');form.submit()</script>"  return payStr, nil}

三、异步通知

数据解密、签名校验

// 异步通知信息解密type NotifyQuery struct {  XMLName xml.Name   `xml:"jdpay" json:"-"`  Version string    `xml:"version" json:"version"`  // 版本号  Merchant string    `xml:"merchant" json:"merchant"` // 商户号  Result  NotifyResult `xml:"result" json:"result"`   // 交易结果  Encrypt string    `xml:"encrypt" json:"encrypt"`  // 加密信息}type NotifyDecrypt struct {  XMLName  xml.Name   `xml:"jdpay" json:"-"`  Version  string    `xml:"version" json:"version"`   // 版本号  Merchant string    `xml:"merchant" json:"merchant"`  // 商户号  Result  NotifyResult `xml:"result" json:"result"`    // 交易结果  TradeNum string    `xml:"tradeNum" json:"tradeNum"`  // 订单号  TradeType int      `xml:"tradeType" json:"tradeType"` // 交易类型  Sign   string    `xml:"sign" json:"sign"`      // 数据签名  Amount  int64     `xml:"amount" json:"amount"`    // 人民币支付总金额  OrderId  string    `json:"order_id"`         // 京东交易流水号  Status  string    `xml:"status" json:"status"`    // 交易状态  PayList  NotifyPayList `xml:"payList" json:"payList"`   // 支付方式明细}type NotifyResult struct {  Code string `xml:"code" json:"code"` // 交易返回码  Desc string `xml:"desc" json:"desc"` // 返回码信息}type NotifyPayList struct {  Pay []NotifyPay `xml:"pay" json:"pay"`}type NotifyPay struct {  PayType  int  `xml:"payType" json:"payType"`   // 支付方式  Amount  int64 `xml:"amount" json:"amount"`    // 交易金额  Currency string `xml:"currency" json:"currency"`  // 交易币种  TradeTime string `xml:"tradeTime" json:"tradeTime"` // 交易时间}// 异步通知信息解密func notifyDataDecrypt(rawPost string) (notifyDecrypt NotifyDecrypt, err error) {  // 解析加密的支付机构参数为结构体  var notifyQuery NotifyQuery  err = xml.Unmarshal([]byte(rawPost), &notifyQuery)  if err != nil {    return notifyDecrypt, err  }  // 解密支付机构参数  decryptBytes, err := decryptArg(notifyQuery, desKey)  if err != nil {    return notifyDecrypt, err  }  // 解析解密后的支付机构参数为结构体  err = xml.Unmarshal(decryptBytes, &notifyDecrypt)  if err != nil {    return notifyDecrypt, err  }  // 证书  publicKey, err := getKey("public_key")  if err != nil {    return notifyDecrypt, err  }  // 校验签名  if !checkSign(decryptBytes, notifyDecrypt.Sign, publicKey) {    return notifyDecrypt, err  }  return notifyDecrypt, nil}

四、交易查询

查询订单

type SearchWithoutSignRequest struct {  XMLName  xml.Name `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"` // 原交易流水号  TradeType string  `xml:"tradeType" json:"tradeType"` // 交易类型}type SearchWithSignRequest struct {  XMLName  xml.Name `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"` // 原交易流水号  TradeType string  `xml:"tradeType" json:"tradeType"` // 交易类型  Sign   string  `xml:"sign" json:"sign"`      // 签名}type SearchResult struct {  XMLName xml.Name    `xml:"jdpay" json:"-"`  Version string     `xml:"version" json:"version"`  // 版本号  Merchant string     `xml:"merchant" json:"merchant"` // 商户号  Result  SearchResultRsp `xml:"result" json:"result"`   // 交易结果  Encrypt string     `xml:"encrypt" json:"encrypt"`  // 加密信息}type SearchResultRsp struct {  Code string `xml:"code" json:"code"` // 交易返回码  Desc string `xml:"desc" json:"desc"` // 返回码信息}type SearchDecryptRsp struct {  XMLName  xml.Name     `xml:"jdpay" json:"-"`  Merchant string      `xml:"merchant" json:"merchant"`  // 商户号  TradeNum string      `xml:"tradeNum" json:"tradeNum"`  // 订单编号  TradeType string      `xml:"tradeType" json:"tradeType"` // 交易类型  Result  SearchResultRsp `xml:"result" json:"result"`    // 交易结果  Sign   string      `xml:"sign" json:"sign"`      // 数据签名  Amount  int64      `xml:"amount" json:"amount"`    // 人民币支付总金额  Status  string      `xml:"status" json:"status"`    // 交易状态  PayList  SearchPayListRsp `xml:"payList" json:"payList"`   // 支付方式明细}type SearchPayListRsp struct {  Pay []SearchPayRsp `xml:"pay" json:"pay"`}type SearchPayRsp struct {  PayType  int  `xml:"payType" json:"payType"`   // 支付方式  Amount  int64 `xml:"amount" json:"amount"`    // 交易金额  Currency string `xml:"currency" json:"currency"`  // 交易币种  TradeTime string `xml:"tradeTime" json:"tradeTime"` // 交易时间}const tradeWayUrl = "https://paygate.jd.com/service/query"const customTradeType = "0" // 交易类型const successCode = "000000"func searchTrade(orderId string) (searchDecryptRsp SearchDecryptRsp, err error) {  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")  if err != nil {    return searchDecryptRsp, err  }  // 签名  sign, err := getRsaSign(xmlStr, privateKey)  if err != nil {    return searchDecryptRsp, 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)  if err != nil {    return searchDecryptRsp, err  }  encryptBytes, err := tripleEcbDesEncrypt([]byte(xmlStr), desKeyBytes)  if err != nil {    return searchDecryptRsp, err  }  reqEncrypt := decimalByteSlice2HexString(encryptBytes)  reqEncrypt = base64.StdEncoding.EncodeToString([]byte(reqEncrypt))  searchWithEncrypt := ReqWithEncrypt{    Version: version,    Merchant: merchantId,    Encrypt: reqEncrypt,  }  xmlBytes, err = xml.Marshal(searchWithEncrypt)  if err != nil {    return searchDecryptRsp, err  }  xmlStr = strings.TrimRight(xml.Header, "\n") + string(xmlBytes)  request, err := http.NewRequest(http.MethodPost, tradeWayUrl, strings.NewReader(xmlStr))  if err != nil {    return searchDecryptRsp, err  }  request.Header.Add("content-type", "application/xml; charset=utf-8")  client := http.DefaultClient  response, err := client.Do(request)  if err != nil {    return searchDecryptRsp, err  }  defer response.Body.Close()  bodyBytes, err := ioutil.ReadAll(response.Body)  if err != nil {    return searchDecryptRsp, err  }  searchResult := new(SearchResult)  if err = xml.Unmarshal(bodyBytes, searchResult); err != nil {    return searchDecryptRsp, err  }  if searchResult.Result.Code != successCode {    return searchDecryptRsp, errors.New(searchResult.Result.Desc)  }  // 解密数据  rspEncryptBytes, err := base64.StdEncoding.DecodeString(searchResult.Encrypt)  rspEncryptBytes, err = hexString2Bytes(string(rspEncryptBytes))  if err != nil {    return searchDecryptRsp, err  }  rspDecryptBytes, err := tripleEcbDesDecrypt(rspEncryptBytes, desKeyBytes)  if err != nil {    return searchDecryptRsp, err  }  err = xml.Unmarshal(rspDecryptBytes, &searchDecryptRsp)  if err != nil {    return searchDecryptRsp, err  }  // 证书  publicKey, err := getKey("public_key")  if err != nil {    return searchDecryptRsp, err  }  // 校验签名  if !checkSign(rspDecryptBytes, searchDecryptRsp.Sign, publicKey) {    return searchDecryptRsp, err  }  return searchDecryptRsp, nil}

五、申请退款

申请退款

// 退款type 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.Name `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.Name `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.Name      `xml:"jdpay" json:"-"`  Version string       `xml:"version" json:"version"`  // 版本号  Merchant string       `xml:"merchant" json:"merchant"` // 商户号  Result  RefundPayResultRsp `xml:"result" json:"result"`   // 退款结果  Encrypt string       `xml:"encrypt" json:"encrypt"`  // 加密信息}type RefundPayResultRsp struct {  Code string `xml:"code" json:"code"` // 交易返回码  Desc string `xml:"desc" json:"desc"` // 返回码信息}type RefundPayDecryptRsp struct {  XMLName  xml.Name      `xml:"jdpay" json:"-"`  Version  string       `xml:"version" json:"version"`  // 版本号  Merchant string       `xml:"merchant" json:"merchant"` // 商户号  TradeNum string       `xml:"tradeNum" json:"tradeNum"`  TradeType string       `xml:"tradeType"json:"tradeType"`  Result  RefundPayResultRsp `xml:"result" json:"result"` // 退款结果  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 = "https://paygate.jd.com/service/refund"// 申请退款func refundTrade(orderId string, amount float64) (refundPayDecryptRsp RefundPayDecryptRsp, err error) {  totalFee, err := strconv.ParseUint(fmt.Sprintf("%.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 := xml.Marshal(refundReqWithoutSign)  xmlStr := xml.Header + string(xmlBytes)  xmlStr = replaceXmlStrBlankChar(xmlStr)  // 证书  privateKey, err := getKey("private_key")  if err != nil {    return refundPayDecryptRsp, err  }  // 签名  sign, err := getRsaSign(xmlStr, privateKey)  if err != nil {    return refundPayDecryptRsp, 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)  if err != nil {    return refundPayDecryptRsp, err  }  encryptBytes, err := tripleEcbDesEncrypt([]byte(xmlStr), desKeyBytes)  if err != nil {    return refundPayDecryptRsp, 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))  if err != nil {    return refundPayDecryptRsp, err  }  request.Header.Add("content-type", "application/xml; charset=utf-8")  client := http.DefaultClient  response, err := client.Do(request)  if err != nil {    return refundPayDecryptRsp, err  }  defer response.Body.Close()  bodyBytes, err := ioutil.ReadAll(response.Body)  if err != nil {    return refundPayDecryptRsp, err  }  refundResult := new(RefundResult)  if err = xml.Unmarshal(bodyBytes, refundResult); err != nil {    return refundPayDecryptRsp, err  }  // 解密数据  rspEncryptBytes, err := base64.StdEncoding.DecodeString(refundResult.Encrypt)  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 = xml.Unmarshal(rspDecryptBytes, &refundPayDecryptRsp)  if err != nil {    return refundPayDecryptRsp, err  }    // 证书  publicKey, err := getKey("public_key")  if err != nil {    return refundPayDecryptRsp, err  }  // 校验签名  if !checkSign(rspDecryptBytes, refundPayDecryptRsp.Sign, publicKey) {    return refundPayDecryptRsp, err  }    return refundPayDecryptRsp, nil}

到此这篇关于使用golang怎么实现一个京东支付功能的文章就介绍到这了,更多相关使用golang怎么实现一个京东支付功能的内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: 使用golang怎么实现一个京东支付功能

本文链接: https://lsjlt.com/news/247930.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 使用golang怎么实现一个京东支付功能
    这篇文章主要介绍了使用golang怎么实现一个京东支付功能,此处通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考价值,需要的朋友可以参考下:什么是golanggolang 是Google开发的一种静态强类型、编译型、并发型...
    99+
    2023-06-06
  • 利用golang怎么实现一个微信支付功能
    本文章向大家介绍利用golang怎么实现一个微信支付功能的基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。golang的优点有哪些golang是一种编译语言,可以将代码编译为机器代码,编译后的二进制文件可以直接部署...
    99+
    2023-06-06
  • golang实现支付功能
    随着电商时代的到来,支付功能已经成为了很多网站和APP必备的功能。其中,golang作为一个高效的编程语言,已经得到了很多开发人员的青睐。本文将介绍如何使用golang来实现支付功能。注册支付账号首先,我们要注册一个支付账号并获得相应的AP...
    99+
    2023-05-14
  • 怎么在HTML5中使用tracking.js实现一个刷脸支付功能
    怎么在HTML5中使用tracking.js实现一个刷脸支付功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。摄像头1.1input获取摄像头html5中获取用户摄像头,有...
    99+
    2023-06-09
  • 利用javaweb实现一个在线支付功能
    今天就跟大家聊聊有关利用javaweb实现一个在线支付功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。具体内容如下package com.learning.web.servlet;...
    99+
    2023-05-31
    javaweb 在线支付 ava
  • 怎么用Android实现京东秒杀功能
    这篇“怎么用Android实现京东秒杀功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么用Android实现京东秒杀功能...
    99+
    2023-06-29
  • 使用java如何实现一个微信H5支付功能
    这篇文章将为大家详细讲解有关使用java如何实现一个微信H5支付功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。前面做了app微信支付的回调处理,现在需要做微信公众号的支付,花了一天多时间...
    99+
    2023-05-31
    h5支付 java
  • Vue怎么实现支付功能
    这篇“Vue怎么实现支付功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Vue怎么实现支付功能”文章吧。 代码如...
    99+
    2023-07-04
  • Java 实现订单未支付超时自动取消功能(京东商城为例)
    目录创建 TimerTaskTimer 定时器调用 TimerTask总结源码在电商上购买商品后,如果在下单而又没有支付的情况下,一般提示30分钟完成支付,否则订单自动。比如在京东下...
    99+
    2024-04-02
  • 使用Python怎么实现一个京东抢秒杀效果
    这篇文章将为大家详细讲解有关使用Python怎么实现一个京东抢秒杀效果,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。python是什么意思Python是一种跨平台的、具有解释性、编译性、互动...
    99+
    2023-06-14
  • Android中怎么接入支付宝实现支付功能
    本篇文章为大家展示了Android中怎么接入支付宝实现支付功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1.登录官网他的官网就是蚂蚁金服的开放平台了,我们可以访问 蚂蚁金服开放平台 ,并且注册账...
    99+
    2023-05-31
    android
  • 怎么用Java也实现微信和支付宝支付功能
    这篇文章主要介绍“怎么用Java也实现微信和支付宝支付功能”,在日常操作中,相信很多人在怎么用Java也实现微信和支付宝支付功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2024-04-02
  • 用Android实现京东秒杀功能详解
    首先看效果图: 京东秒杀是两个小时一个场次,我们获取到场次后,通过场次+两个小时后,获取到最终的时间,拿最终时间的时间戳,与当前时间时间戳相减,求得剩余的小时,分钟,秒数,即可实现...
    99+
    2024-04-02
  • Android中怎么实现微信支付功能
    Android中怎么实现微信支付功能,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 去微信开放平台申请微信支付服务,绑定自己的应用这里具体不多讲,但是一定要申请完成,将会得到是...
    99+
    2023-05-31
    android
  • 使用golang怎么实现一个登录验证码功能
    这篇文章将为大家详细讲解有关使用golang怎么实现一个登录验证码功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。golang适合做什么golang可以做服务器端开发,但golang很适合...
    99+
    2023-06-06
  • 使用golang怎么实现一个比特币交易功能
    使用golang怎么实现一个比特币交易功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。比特币交易交易(transaction)是比特币的核心所在,而区块链唯一的目的,也正...
    99+
    2023-06-15
  • Golang怎么使用channel实现一个优雅退出功能
    这篇文章主要介绍了Golang怎么使用channel实现一个优雅退出功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang怎么使用channel实现一个优雅退出功能文章都会有所收获,下面我们一起来看看吧...
    99+
    2023-07-05
  • Python中怎么实现一个支付接口
    这篇文章给大家介绍Python中怎么实现一个支付接口,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。首先定义数据如下:用的测试平台的数据data=[   "", ...
    99+
    2023-06-17
  • 怎么用PHP实现支付宝和微信扫码在线支付的功能
    本篇内容介绍了“怎么用PHP实现支付宝和微信扫码在线支付的功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成...
    99+
    2024-04-02
  • 怎么用php实现支付宝支付
    本文操作环境:Windows7系统、PHP7.4版、DELL G3电脑怎么用php实现支付宝支付?PHP实现支付宝支付:提示:这里的demo使用的时沙箱支付 需要先注册沙箱账号等注册沙箱账号:首先扫码登录支付宝开放平台注册 地址:https...
    99+
    2021-05-21
    PHP 支付宝支付
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作