service_api.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package qq
  2. import (
  3. "crypto/tls"
  4. "encoding/json"
  5. "encoding/xml"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "net/http"
  11. "reflect"
  12. "strings"
  13. "github.com/iGoogle-ink/gopay"
  14. )
  15. // 向QQ发送Post请求,对于本库未提供的微信API,可自行实现,通过此方法发送请求
  16. // bm:请求参数的BodyMap
  17. // url:完整url地址,例如:https://qpay.qq.com/cgi-bin/pay/qpay_unified_order.cgi
  18. // tlsConfig:tls配置,如无需证书请求,传nil
  19. func (q *Client) PostRequest(bm gopay.BodyMap, url string, tlsConfig *tls.Config) (bs []byte, err error) {
  20. return q.doQQ(bm, url, tlsConfig)
  21. }
  22. // 解析QQ支付异步通知的结果到BodyMap
  23. // req:*http.Request
  24. // 返回参数bm:Notify请求的参数
  25. // 返回参数err:错误信息
  26. func ParseNotifyToBodyMap(req *http.Request) (bm gopay.BodyMap, err error) {
  27. bs, err := ioutil.ReadAll(io.LimitReader(req.Body, int64(2<<20))) // default 2MB change the size you want;
  28. if err != nil {
  29. return nil, fmt.Errorf("ioutil.ReadAll:%w", err)
  30. }
  31. bm = make(gopay.BodyMap)
  32. if err = xml.Unmarshal(bs, &bm); err != nil {
  33. return nil, fmt.Errorf("xml.Unmarshal(%s):%w", string(bs), err)
  34. }
  35. return
  36. }
  37. // 解析QQ支付异步通知的参数
  38. // req:*http.Request
  39. // 返回参数notifyReq:Notify请求的参数
  40. // 返回参数err:错误信息
  41. func ParseNotify(req *http.Request) (notifyReq *NotifyRequest, err error) {
  42. notifyReq = new(NotifyRequest)
  43. if err = xml.NewDecoder(req.Body).Decode(notifyReq); err != nil {
  44. return nil, fmt.Errorf("xml.NewDecoder.Decode:%w", err)
  45. }
  46. return
  47. }
  48. // QQ同步返回参数验签或异步通知参数验签
  49. // ApiKey:API秘钥值
  50. // signType:签名类型(调用API方法时填写的类型)
  51. // bean:微信同步返回的结构体 qqRsp 或 异步通知解析的结构体 notifyReq
  52. // 返回参数ok:是否验签通过
  53. // 返回参数err:错误信息
  54. func VerifySign(apiKey, signType string, bean interface{}) (ok bool, err error) {
  55. if apiKey == gopay.NULL || signType == gopay.NULL {
  56. return false, errors.New("apiKey or signType can not null")
  57. }
  58. if bean == nil {
  59. return false, errors.New("bean is nil")
  60. }
  61. kind := reflect.ValueOf(bean).Kind()
  62. if kind == reflect.Map {
  63. bm := bean.(gopay.BodyMap)
  64. bodySign := bm.Get("sign")
  65. bm.Remove("sign")
  66. return getReleaseSign(apiKey, signType, bm) == bodySign, nil
  67. }
  68. bs, err := json.Marshal(bean)
  69. if err != nil {
  70. return false, fmt.Errorf("json.Marshal(%s):%w", string(bs), err)
  71. }
  72. bm := make(gopay.BodyMap)
  73. if err = json.Unmarshal(bs, &bm); err != nil {
  74. return false, fmt.Errorf("json.Marshal(%s):%w", string(bs), err)
  75. }
  76. bodySign := bm.Get("sign")
  77. bm.Remove("sign")
  78. return getReleaseSign(apiKey, signType, bm) == bodySign, nil
  79. }
  80. type NotifyResponse struct {
  81. ReturnCode string `xml:"return_code"`
  82. ReturnMsg string `xml:"return_msg"`
  83. }
  84. // 返回数据给QQ
  85. func (w *NotifyResponse) ToXmlString() (xmlStr string) {
  86. var buffer strings.Builder
  87. buffer.WriteString("<xml><return_code>")
  88. buffer.WriteString(w.ReturnCode)
  89. buffer.WriteString("</return_code>")
  90. if w.ReturnMsg != gopay.NULL {
  91. buffer.WriteString("<return_msg>")
  92. buffer.WriteString(w.ReturnMsg)
  93. buffer.WriteString("</return_msg>")
  94. }
  95. buffer.WriteString("</xml>")
  96. xmlStr = buffer.String()
  97. return
  98. }