@@ -8,6 +8,7 @@ package wx
8
8
9
9
import (
10
10
"bytes"
11
+ "crypto/sha256"
11
12
"crypto/x509"
12
13
"encoding/json"
13
14
"errors"
@@ -16,6 +17,7 @@ import (
16
17
"io/ioutil"
17
18
"log"
18
19
"net/http"
20
+ "path"
19
21
"strings"
20
22
"time"
21
23
)
@@ -98,6 +100,81 @@ func (mr *mchReqV3) Do(method string) (err error) {
98
100
}
99
101
}
100
102
103
+ // Upload 上传图片视频
104
+ func (mr * mchReqV3 ) Upload (fileName string , raw []byte ) (err error ) {
105
+ // 准备证书
106
+ if len (wechatPayCerts ) == 0 {
107
+ wechatPayCerts ["" ] = nil
108
+ if err = mr .account .DownloadV3Cert (); err != nil {
109
+ return
110
+ }
111
+ }
112
+ // 准备描述
113
+ s := sha256 .New ()
114
+ s .Write (raw )
115
+ meta , err := json .Marshal (H {"filename" : fileName , "sha256" : fmt .Sprintf ("%X" , s .Sum (nil ))})
116
+ if err != nil {
117
+ return
118
+ }
119
+ // 开始构建请求体
120
+ // 微信不承认golang 自带的 multipart 规范
121
+ var body = new (bytes.Buffer )
122
+ var nonce = NewRandStr (23 )
123
+ var boundary = fmt .Sprintf ("--%v\r \n " , nonce )
124
+ body .WriteString (boundary )
125
+ body .WriteString ("Content-Disposition: form-data; name=\" meta\" ;\r \n " )
126
+ body .WriteString ("Content-Type: application/json\r \n \r \n " )
127
+ body .Write (meta )
128
+ body .WriteString ("\r \n " )
129
+ body .WriteString (boundary )
130
+ body .WriteString (fmt .Sprintf ("Content-Disposition: form-data; name=\" file\" ; filename=\" %v\" ;\r \n " , fileName ))
131
+ body .WriteString (fmt .Sprintf ("Content-Type: image/%v\r \n \r \n " , path .Ext (fileName )))
132
+ body .Write (raw )
133
+ body .WriteString ("\r \n " )
134
+ body .WriteString (fmt .Sprintf ("--%v--\r \n " , nonce ))
135
+
136
+ // 构建API地址
137
+ api := fmt .Sprintf ("https://api.mch.weixin.qq.com/v3/%v" , mr .api )
138
+ if strings .HasPrefix (string (mr .api ), "http" ) {
139
+ api = string (mr .api )
140
+ }
141
+ // 构建请求
142
+ req , err := http .NewRequest (http .MethodPost , api , bytes .NewReader (body .Bytes ()))
143
+ if err != nil {
144
+ return
145
+ }
146
+ // 签名
147
+ if err = mr .sign (req , meta ); err != nil {
148
+ return
149
+ }
150
+ req .Header .Set ("Content-Type" , "multipart/form-data" )
151
+ // 网络操作
152
+ resp , err := client ().Do (req )
153
+ if err != nil {
154
+ return
155
+ }
156
+
157
+ // 处理结果
158
+ raw , err = ioutil .ReadAll (resp .Body )
159
+ if err != nil {
160
+ return
161
+ }
162
+ if resp .StatusCode != http .StatusOK && resp .StatusCode != http .StatusAccepted && resp .StatusCode != http .StatusNoContent {
163
+ var rs mch_api_v3.ErrorResp
164
+ _ = json .Unmarshal (raw , & rs )
165
+ log .Println (api , rs , resp .Header .Get ("Request-ID" ))
166
+ return errors .New (fmt .Sprintf ("%v | Request-ID:%v" , rs .Message , resp .Header .Get ("Request-ID" )))
167
+ }
168
+ if err = mr .account .VerifyV3 (resp , raw ); err != nil {
169
+ return
170
+ }
171
+ if resp .StatusCode == http .StatusOK {
172
+ return json .Unmarshal (raw , & mr .res )
173
+ } else {
174
+ return
175
+ }
176
+ }
177
+
101
178
func (mr * mchReqV3 ) sign (request * http.Request , body []byte ) (err error ) {
102
179
request .Header .Set ("User-Agent" , "Gdb/1.0" )
103
180
request .Header .Set ("Content-Type" , "application/json" )
@@ -115,5 +192,9 @@ func (mr *mchReqV3) sign(request *http.Request, body []byte) (err error) {
115
192
}
116
193
request .Header .Set ("Authorization" , fmt .Sprintf (`WECHATPAY2-SHA256-RSA2048 mchid="%v",nonce_str="%v",signature="%v",timestamp="%v",serial_no="%X"` ,
117
194
mr .account .MchId , nonce , sign , ts , mr .account .certX509 .SerialNumber ))
195
+ //log.Println(fmt.Sprintf("%v\n%v\n%v\n%v\n%v\n", request.Method,
196
+ // request.URL.Path, ts, nonce, string(body)))
197
+ //log.Println("Authorization", fmt.Sprintf(`WECHATPAY2-SHA256-RSA2048 mchid="%v",nonce_str="%v",signature="%v",timestamp="%v",serial_no="%X"`,
198
+ // mr.account.MchId, nonce, sign, ts, mr.account.certX509.SerialNumber))
118
199
return
119
200
}
0 commit comments