func EncodeXMLResponseMessage(w io.Writer, msg map[string]string) (err error) { var buf bytes.Buffer if err = util.EncodeXMLFromMap(&buf, msg, "xml"); err != nil { return } log.Printf("[WECHAT_DEBUG] [MCH] [CALLBACK] http response body:\n%s\n", buf.Bytes()) _, err = buf.WriteTo(w) return }
// 下载对账单到 io.Writer. func downloadBillToWriter(writer io.Writer, req map[string]string, httpClient *http.Client) (written int64, err error) { if httpClient == nil { httpClient = http.DefaultClient } buf := make([]byte, 32*1024) // 与 io.copyBuffer 里的默认大小一致 reqBuf := bytes.NewBuffer(buf[:0]) if err = util.EncodeXMLFromMap(reqBuf, req, "xml"); err != nil { return } httpResp, err := httpClient.Post("https://api.mch.weixin.qq.com/pay/downloadbill", "text/xml; charset=utf-8", reqBuf) if err != nil { return } defer httpResp.Body.Close() if httpResp.StatusCode != http.StatusOK { err = fmt.Errorf("http.Status: %s", httpResp.Status) return } n, err := io.ReadFull(httpResp.Body, buf) switch { case err == nil: // n == len(buf), 可以认为返回的是对账单而不是xml格式的错误信息 written, err = bytes.NewReader(buf).WriteTo(writer) if err != nil { return } var n2 int64 n2, err = io.CopyBuffer(writer, httpResp.Body, buf) written += n2 return case err == io.ErrUnexpectedEOF: readBytes := buf[:n] if index := bytes.Index(readBytes, downloadBillErrorRootNodeStartElement); index != -1 { if bytes.Contains(readBytes[index+len(downloadBillErrorRootNodeStartElement):], downloadBillErrorReturnCodeNodeStartElement) { // 可以认为是错误信息了, 尝试解析xml var result core.Error if err = xml.Unmarshal(readBytes, &result); err == nil { err = &result return } // err != nil 执行默认的动作, 写入 writer } } return bytes.NewReader(readBytes).WriteTo(writer) case err == io.EOF: // 返回空的body err = nil return default: // 其他的错误 return } }
// 微信支付通用请求方法. // 注意: err == nil 表示协议状态都为 SUCCESS(return_code == SUCCESS). func (pxy *Proxy) PostXML(url string, req map[string]string) (resp map[string]string, err error) { bodyBuf := textBufferPool.Get().(*bytes.Buffer) bodyBuf.Reset() defer textBufferPool.Put(bodyBuf) if err = util.EncodeXMLFromMap(bodyBuf, req, "xml"); err != nil { return } httpResp, err := pxy.httpClient.Post(url, "text/xml; charset=utf-8", bodyBuf) if err != nil { return } defer httpResp.Body.Close() if httpResp.StatusCode != http.StatusOK { err = fmt.Errorf("http.Status: %s", httpResp.Status) return } if resp, err = util.DecodeXMLToMap(httpResp.Body); err != nil { return } // 判断协议状态 ReturnCode, ok := resp["return_code"] if !ok { err = errors.New("no return_code parameter") return } if ReturnCode != ReturnCodeSuccess { err = &Error{ ReturnCode: ReturnCode, ReturnMsg: resp["return_msg"], } return } // 安全考虑, 做下验证 appId, ok := resp["appid"] if ok && appId != pxy.appId { err = fmt.Errorf("appid mismatch, have: %q, want: %q", appId, pxy.appId) return } mchId, ok := resp["mch_id"] if ok && mchId != pxy.mchId { err = fmt.Errorf("mch_id mismatch, have: %q, want: %q", mchId, pxy.mchId) return } // 认证签名 signature1, ok := resp["sign"] if !ok { err = errors.New("no sign parameter") return } signature2 := Sign(resp, pxy.apiKey, nil) if signature1 != signature2 { err = fmt.Errorf("check signature failed, \r\ninput: %q, \r\nlocal: %q", signature1, signature2) return } return }
// PostXML 是微信支付通用请求方法. // err == nil 表示协议状态为 SUCCESS(return_code==SUCCESS). func (clt *Client) PostXML(url string, req map[string]string) (resp map[string]string, err error) { bodyBuf := textBufferPool.Get().(*bytes.Buffer) bodyBuf.Reset() defer textBufferPool.Put(bodyBuf) if err = util.EncodeXMLFromMap(bodyBuf, req, "xml"); err != nil { return } api.DebugPrintPostXMLRequest(url, bodyBuf.Bytes()) httpResp, err := clt.httpClient.Post(url, "text/xml; charset=utf-8", bodyBuf) if err != nil { return } defer httpResp.Body.Close() if httpResp.StatusCode != http.StatusOK { err = fmt.Errorf("http.Status: %s", httpResp.Status) return } if resp, err = api.DecodeXMLHttpResponse(httpResp.Body); err != nil { return } // 判断协议状态 returnCode, ok := resp["return_code"] if !ok { err = ErrNotFoundReturnCode return } if returnCode != ReturnCodeSuccess { err = &Error{ ReturnCode: returnCode, ReturnMsg: resp["return_msg"], } return } // 安全考虑, 做下验证 appid 和 mch_id appId, ok := resp["appid"] if ok && appId != clt.appId { err = fmt.Errorf("appid mismatch, have: %s, want: %s", appId, clt.appId) return } mchId, ok := resp["mch_id"] if ok && mchId != clt.mchId { err = fmt.Errorf("mch_id mismatch, have: %s, want: %s", mchId, clt.mchId) return } // 验证签名 signature1, ok := resp["sign"] if !ok { err = ErrNotFoundSign return } signature2 := Sign(resp, clt.apiKey, nil) if signature1 != signature2 { err = fmt.Errorf("sign mismatch,\nhave: %s,\nwant: %s", signature1, signature2) return } return }
func EncodeXMLResponseMessage(w io.Writer, msg map[string]string) (err error) { return util.EncodeXMLFromMap(w, msg, "xml") }
// Response 回复消息给微信服务器 func (ctx *Context) Response(msg map[string]string) (err error) { return util.EncodeXMLFromMap(ctx.ResponseWriter, msg, "xml") }