蛋蛋星球-制度模式
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

102 lignes
2.9 KiB

  1. /*
  2. QQ 支付
  3. 文档:https://qpay.qq.com/buss/doc.shtml
  4. */
  5. package qq
  6. import (
  7. "encoding/json"
  8. "encoding/xml"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "net/http"
  13. "reflect"
  14. "strings"
  15. "github.com/go-pay/gopay"
  16. )
  17. // ParseNotifyToBodyMap 解析QQ支付异步通知的结果到BodyMap
  18. // req:*http.Request
  19. // 返回参数bm:Notify请求的参数
  20. // 返回参数err:错误信息
  21. func ParseNotifyToBodyMap(req *http.Request) (bm gopay.BodyMap, err error) {
  22. bs, err := io.ReadAll(io.LimitReader(req.Body, int64(3<<20))) // default 3MB change the size you want;
  23. if err != nil {
  24. return nil, fmt.Errorf("io.ReadAll:%w", err)
  25. }
  26. bm = make(gopay.BodyMap)
  27. if err = xml.Unmarshal(bs, &bm); err != nil {
  28. return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
  29. }
  30. return
  31. }
  32. // Deprecated
  33. // 推荐使用 ParseNotifyToBodyMap
  34. func ParseNotify(req *http.Request) (notifyReq *NotifyRequest, err error) {
  35. notifyReq = new(NotifyRequest)
  36. if err = xml.NewDecoder(req.Body).Decode(notifyReq); err != nil {
  37. return nil, fmt.Errorf("xml.NewDecoder.Decode:%w", err)
  38. }
  39. return
  40. }
  41. // VerifySign QQ同步返回参数验签或异步通知参数验签
  42. //
  43. // ApiKey:API秘钥值
  44. // signType:签名类型(调用API方法时填写的类型)
  45. // bean:微信同步返回的结构体 qqRsp 或 异步通知解析的结构体 notifyReq
  46. // 返回参数ok:是否验签通过
  47. // 返回参数err:其他错误信息,不要根据 error 是否为空来判断验签正确与否,需再单独判断返回的 ok
  48. func VerifySign(apiKey, signType string, bean any) (ok bool, err error) {
  49. if apiKey == gopay.NULL || signType == gopay.NULL {
  50. return false, errors.New("apiKey or signType can not null")
  51. }
  52. if bean == nil {
  53. return false, errors.New("bean is nil")
  54. }
  55. kind := reflect.ValueOf(bean).Kind()
  56. if kind == reflect.Map {
  57. bm := bean.(gopay.BodyMap)
  58. bodySign := bm.GetString("sign")
  59. bm.Remove("sign")
  60. return GetReleaseSign(apiKey, signType, bm) == bodySign, nil
  61. }
  62. bs, err := json.Marshal(bean)
  63. if err != nil {
  64. return false, fmt.Errorf("[%w]: %v, value: %v", gopay.MarshalErr, err, bean)
  65. }
  66. bm := make(gopay.BodyMap)
  67. if err = json.Unmarshal(bs, &bm); err != nil {
  68. return false, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
  69. }
  70. bodySign := bm.GetString("sign")
  71. bm.Remove("sign")
  72. return GetReleaseSign(apiKey, signType, bm) == bodySign, nil
  73. }
  74. type NotifyResponse struct {
  75. ReturnCode string `xml:"return_code"`
  76. ReturnMsg string `xml:"return_msg"`
  77. }
  78. // ToXmlString 返回数据给QQ
  79. func (w *NotifyResponse) ToXmlString() (xmlStr string) {
  80. var buffer strings.Builder
  81. buffer.WriteString("<xml><return_code>")
  82. buffer.WriteString(w.ReturnCode)
  83. buffer.WriteString("</return_code>")
  84. if w.ReturnMsg != gopay.NULL {
  85. buffer.WriteString("<return_msg>")
  86. buffer.WriteString(w.ReturnMsg)
  87. buffer.WriteString("</return_msg>")
  88. }
  89. buffer.WriteString("</xml>")
  90. xmlStr = buffer.String()
  91. return
  92. }