// 微信支付通用请求方法. // 注意: err == nil 表示协议状态都为 SUCCESS. func (proxy *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.FormatMapToXML(bodyBuf, req); err != nil { return } LogInfoln("[WECHAT_DEBUG] request url:", url) LogInfoln("[WECHAT_DEBUG] request xml:", bodyBuf.String()) httpResp, err := proxy.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 } respBody, err := ioutil.ReadAll(httpResp.Body) if err != nil { return } LogInfoln("[WECHAT_DEBUG] response xml:", string(respBody)) if resp, err = util.ParseXMLToMap(bytes.NewReader(respBody)); 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 } // 认证签名 signature1, ok := resp["sign"] if !ok { err = errors.New("no sign parameter") return } signature2 := Sign(resp, proxy.apiKey, nil) if signature1 != signature2 { err = fmt.Errorf("check signature failed, \r\ninput: %q, \r\nlocal: %q", signature1, signature2) return } 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.FormatMapToXML(reqBuf, req); 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 = 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 mch.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. 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.FormatMapToXML(bodyBuf, req); err != nil { return } 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 = util.ParseXMLToMap(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 } // 认证签名 signature1, ok := resp["sign"] if !ok { err = errors.New("no sign parameter") return } signature2 := Sign(resp, clt.apiKey, nil) if signature1 != signature2 { err = fmt.Errorf("check signature failed, \r\ninput: %q, \r\nlocal: %q", signature1, signature2) return } return }
// 下载对账单. func DownloadBill(req map[string]string, httpClient *http.Client) (data []byte, err error) { if httpClient == nil { httpClient = http.DefaultClient } bodyBuf := bytes.NewBuffer(make([]byte, 0, 1024)) if err = util.FormatMapToXML(bodyBuf, req); err != nil { return } httpResp, err := httpClient.Post("https://api.mch.weixin.qq.com/pay/downloadbill", "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 } respBody, err := ioutil.ReadAll(httpResp.Body) if err != nil { return } var result mch.Error if err = xml.Unmarshal(respBody, &result); err == nil { err = &result return } data = respBody err = nil return }
// 下载对账单. func (clt *Client) DownloadBill(req map[string]string) (data []byte, err error) { bodyBuf := textBufferPool.Get().(*bytes.Buffer) bodyBuf.Reset() defer textBufferPool.Put(bodyBuf) if err = util.FormatMapToXML(bodyBuf, req); err != nil { return } url := "https://api.mch.weixin.qq.com/pay/downloadbill" 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 } respBody, err := ioutil.ReadAll(httpResp.Body) if err != nil { return } var result Error if err = xml.Unmarshal(respBody, &result); err == nil { err = &result return } data = respBody err = nil return }
// 微信支付通用请求方法. // 注意: err == nil 表示协议状态都为 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.FormatMapToXML(bodyBuf, req); err != nil { return } debugPrefix := "pay.Client.PostXML" if _, file, line, ok := runtime.Caller(1); ok { debugPrefix += fmt.Sprintf("(called at %s:%d)", file, line) } log.Println(debugPrefix, "request url:", url) log.Println(debugPrefix, "request xml:", bodyBuf.String()) 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 } respBody, err := ioutil.ReadAll(httpResp.Body) if err != nil { return } log.Println(debugPrefix, "response xml:", string(respBody)) if resp, err = util.ParseXMLToMap(bytes.NewReader(respBody)); 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 } // 认证签名 signature1, ok := resp["sign"] if !ok { err = errors.New("no sign parameter") return } signature2 := Sign(resp, clt.apiKey, nil) if signature1 != signature2 { err = fmt.Errorf("check signature failed, \r\ninput: %q, \r\nlocal: %q", signature1, signature2) return } return }