pay.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package pay
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  7. "net/http"
  8. "github.com/astaxie/beego"
  9. "github.com/yaotian/gowechat/server/context"
  10. )
  11. //Pay pay
  12. type Pay struct {
  13. *context.Context
  14. }
  15. //NewPay 实例化
  16. func NewPay(context *context.Context) *Pay {
  17. pay := new(Pay)
  18. pay.Context = context
  19. return pay
  20. }
  21. // UnifiedOrder 统一下单.
  22. func (c *Pay) UnifiedOrder(req map[string]string) (resp map[string]string, err error) {
  23. return c.PostXML("https://api.mch.weixin.qq.com/pay/unifiedorder", req, false)
  24. }
  25. // 查询订单.
  26. func (c *Pay) OrderQuery(req map[string]string) (resp map[string]string, err error) {
  27. return c.PostXML("https://api.mch.weixin.qq.com/pay/orderquery", req, false)
  28. }
  29. // 关闭订单.
  30. func (c *Pay) CloseOrder(req map[string]string) (resp map[string]string, err error) {
  31. return c.PostXML("https://api.mch.weixin.qq.com/pay/closeorder", req, false)
  32. }
  33. // 申请退款.
  34. // NOTE: 请求需要双向证书.
  35. func (c *Pay) Refund(req map[string]string) (resp map[string]string, err error) {
  36. return c.PostXML("https://api.mch.weixin.qq.com/secapi/pay/refund", req, true)
  37. }
  38. // 查询退款.
  39. func (c *Pay) RefundQuery(req map[string]string) (resp map[string]string, err error) {
  40. return c.PostXML("https://api.mch.weixin.qq.com/pay/refundquery", req, false)
  41. }
  42. //PostXML postXML
  43. func (c *Pay) PostXML(url string, req map[string]string, needSSL bool) (resp map[string]string, err error) {
  44. bodyBuf := textBufferPool.Get().(*bytes.Buffer)
  45. bodyBuf.Reset()
  46. defer textBufferPool.Put(bodyBuf)
  47. if err = FormatMapToXML(bodyBuf, req); err != nil {
  48. return
  49. }
  50. //需要ssl,就需要ssl client
  51. client := c.HTTPClient
  52. if needSSL {
  53. client = c.SHTTPClient
  54. }
  55. httpResp, err := client.Post(url, "text/xml; charset=utf-8", bodyBuf)
  56. if err != nil {
  57. return resp, err
  58. }
  59. defer httpResp.Body.Close()
  60. if httpResp.StatusCode != http.StatusOK {
  61. err = fmt.Errorf("http.Status: %s", httpResp.Status)
  62. return
  63. }
  64. respBody, err := ioutil.ReadAll(httpResp.Body)
  65. if err != nil {
  66. return resp, err
  67. }
  68. if resp, err = ParseXMLToMap(bytes.NewReader(respBody)); err != nil {
  69. return
  70. }
  71. beego.Debug(resp)
  72. // 判断协议状态
  73. ReturnCode, ok := resp["return_code"]
  74. if !ok {
  75. err = errors.New("no return_code parameter")
  76. return
  77. }
  78. if ReturnCode != ReturnCodeSuccess {
  79. err = &Error{
  80. ReturnCode: ReturnCode,
  81. ReturnMsg: resp["return_msg"],
  82. }
  83. return
  84. }
  85. // 安全考虑, 做下验证
  86. mchId, ok := resp["mch_id"]
  87. if ok && mchId != c.MchID {
  88. err = fmt.Errorf("mch_id mismatch, have: %q, want: %q", mchId, c.MchID)
  89. return
  90. }
  91. //发送红包的情况,不需要验证这些,因为有的信息没有
  92. if !needSSL {
  93. appId, ok := resp["appid"]
  94. if ok && appId != c.AppID {
  95. err = fmt.Errorf("appid mismatch, have: %q, want: %q", appId, c.AppID)
  96. return
  97. }
  98. // 认证签名
  99. signature1, ok := resp["sign"]
  100. if !ok {
  101. err = errors.New("no sign parameter")
  102. return
  103. }
  104. signature2 := Sign(resp, c.MchAPIKey, nil)
  105. if signature1 != signature2 {
  106. err = fmt.Errorf("check signature failed, \r\ninput: %q, \r\nlocal: %q", signature1, signature2)
  107. return
  108. }
  109. }
  110. return
  111. }