Skip to content

Commit 906da70

Browse files
committed
V3媒体上传接口
1 parent 0979c65 commit 906da70

File tree

7 files changed

+110
-12
lines changed

7 files changed

+110
-12
lines changed

http_client_test.go

+2-5
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,8 @@ func TestMt_RoundTrip(t *testing.T) {
4141
})
4242

4343
var mch = MchAccount{
44-
MchId: "",
45-
MchKey: "",
46-
MchSSLCert: nil,
47-
MchSSLKey: nil,
48-
MchRSAPublicKey: nil,
44+
MchId: "",
45+
MchKey: "",
4946
}
5047
mch.NewMchReq(mch_api.PayOrderQuery)
5148
}

mch.go

-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"fmt"
2626
"github.com/blusewang/wx/mch_api"
2727
"github.com/blusewang/wx/mch_api_v3"
28-
"log"
2928
"net/http"
3029
"strconv"
3130
"time"
@@ -232,7 +231,6 @@ func (ma MchAccount) DownloadV3Cert() (err error) {
232231
if err != nil {
233232
return err
234233
}
235-
log.Println(string(ct))
236234
cb, _ := pem.Decode(ct)
237235
cert, err := x509.ParseCertificate(cb.Bytes)
238236
if err != nil {
@@ -245,10 +243,6 @@ func (ma MchAccount) DownloadV3Cert() (err error) {
245243

246244
// SignBaseV3 V3版通用签名
247245
func (ma MchAccount) SignBaseV3(message string) (sign string, err error) {
248-
//pk, err := ma.getPrivateKey()
249-
//if err != nil {
250-
// return
251-
//}
252246
s := sha256.New()
253247
s.Write([]byte(message))
254248
raw, err := rsa.SignPKCS1v15(rand2.Reader, ma.privateKey, crypto.SHA256, s.Sum(nil))

mch_api_v3/constant.go

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ type MchApiV3 string
1111
const (
1212
// OtherCertificates 获取平台证书列表
1313
OtherCertificates = "certificates"
14+
OtherUploadImage = "merchant/media/upload"
15+
OtherUploadVideo = "merchant/media/video_upload"
1416

1517
// PartnerApplyment4Sub 特约商户进件申请单
1618
PartnerApplyment4Sub = "applyment4sub/applyment/"

mch_api_v3/other.go

+4
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ type OtherCertificatesResp struct {
2121
} `json:"encrypt_certificate"`
2222
} `json:"data"`
2323
}
24+
25+
type OtherUploadResp struct {
26+
MediaId string `json:"media_id"`
27+
}

mch_req_v3.go

+81
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package wx
88

99
import (
1010
"bytes"
11+
"crypto/sha256"
1112
"crypto/x509"
1213
"encoding/json"
1314
"errors"
@@ -16,6 +17,7 @@ import (
1617
"io/ioutil"
1718
"log"
1819
"net/http"
20+
"path"
1921
"strings"
2022
"time"
2123
)
@@ -98,6 +100,81 @@ func (mr *mchReqV3) Do(method string) (err error) {
98100
}
99101
}
100102

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+
101178
func (mr *mchReqV3) sign(request *http.Request, body []byte) (err error) {
102179
request.Header.Set("User-Agent", "Gdb/1.0")
103180
request.Header.Set("Content-Type", "application/json")
@@ -115,5 +192,9 @@ func (mr *mchReqV3) sign(request *http.Request, body []byte) (err error) {
115192
}
116193
request.Header.Set("Authorization", fmt.Sprintf(`WECHATPAY2-SHA256-RSA2048 mchid="%v",nonce_str="%v",signature="%v",timestamp="%v",serial_no="%X"`,
117194
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))
118199
return
119200
}

mch_v3_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package wx
88

99
import (
10+
"bytes"
1011
"crypto"
1112
"crypto/aes"
1213
"crypto/cipher"
@@ -21,11 +22,30 @@ import (
2122
"fmt"
2223
"io/ioutil"
2324
"log"
25+
"mime/multipart"
2426
"net/http"
2527
"testing"
2628
"time"
2729
)
2830

31+
func TestNewRandStrs(t *testing.T) {
32+
log.SetFlags(log.Ltime | log.Lshortfile)
33+
buf := new(bytes.Buffer)
34+
f := multipart.NewWriter(buf)
35+
r, err := f.CreateFormField("meta")
36+
if err != nil {
37+
t.Fatal(err)
38+
}
39+
if err = json.NewEncoder(r).Encode(H{"filename": "x.jpg", "sha256": "435dfslkdjfa;sldkfja;sdf"}); err != nil {
40+
t.Fatal(err)
41+
}
42+
r, err = f.CreateFormFile("file", "file.jpg")
43+
if err != nil {
44+
t.Fatal(err)
45+
}
46+
_, _ = r.Write([]byte("asdfasdf"))
47+
log.Println(buf.String())
48+
}
2949
func TestNewRandStr(t *testing.T) {
3050
log.SetFlags(log.Ltime | log.Lshortfile)
3151
mchId := "1276387801"

mp_req.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (mp *mpReq) Do() (err error) {
111111
return
112112
}
113113

114-
// 上传文档。
114+
// Upload 上传文档。
115115
// reader 一个打开的文件reader。
116116
// fileExtension 该文件的后缀名。
117117
func (mp *mpReq) Upload(reader io.Reader, fileExtension string) (err error) {

0 commit comments

Comments
 (0)