104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
package qywx
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"mime/multipart"
|
||
"net/http"
|
||
"path"
|
||
"time"
|
||
)
|
||
|
||
type Other struct {
|
||
auth *Auth
|
||
}
|
||
|
||
func NewOther(auth *Auth) *Other {
|
||
return &Other{
|
||
|
||
auth: auth,
|
||
}
|
||
}
|
||
|
||
func (g *Other) UploadMediaWithUrl(ctx context.Context, fileUrl, mediaType, corpid, corpsecret string) (uploadRes *UploadMediaRes, err error) {
|
||
// 1. 获取AccessToken
|
||
auth, err := g.auth.GetAccessToken(ctx, corpid, corpsecret)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("获取AccessToken失败: %v", err)
|
||
}
|
||
|
||
// 2. 下载文件
|
||
client := &http.Client{Timeout: 10 * time.Second}
|
||
resp, err := client.Get(fileUrl)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("下载文件失败: %v", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
// 检查响应状态
|
||
if resp.StatusCode != http.StatusOK {
|
||
return nil, fmt.Errorf("下载文件状态码错误: %d", resp.StatusCode)
|
||
}
|
||
|
||
// 3. 准备上传请求(修正点:使用正确的上传API)
|
||
uploadUrl := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=%s",
|
||
auth.AccessToken, mediaType)
|
||
|
||
// 4. 创建multipart表单
|
||
body := &bytes.Buffer{}
|
||
writer := multipart.NewWriter(body)
|
||
|
||
// 从URL提取文件名(或使用默认名)
|
||
filename := path.Base(fileUrl)
|
||
if filename == "/" || filename == "." {
|
||
filename = fmt.Sprintf("file_%d.dat", time.Now().Unix())
|
||
}
|
||
|
||
part, err := writer.CreateFormFile("media", filename)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建表单文件失败: %v", err)
|
||
}
|
||
|
||
// 5. 流式传输文件内容
|
||
if _, err = io.Copy(part, resp.Body); err != nil {
|
||
return nil, fmt.Errorf("写入文件内容失败: %v", err)
|
||
}
|
||
|
||
// 6. 关闭writer
|
||
if err = writer.Close(); err != nil {
|
||
return nil, fmt.Errorf("关闭writer失败: %v", err)
|
||
}
|
||
|
||
// 7. 发送上传请求
|
||
req, err := http.NewRequest("POST", uploadUrl, body)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建请求失败: %v", err)
|
||
}
|
||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||
|
||
uploadResp, err := client.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("上传请求失败: %v", err)
|
||
}
|
||
defer uploadResp.Body.Close()
|
||
|
||
// 8. 解析响应
|
||
respBody, err := io.ReadAll(uploadResp.Body)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||
}
|
||
|
||
if err = json.Unmarshal(respBody, &uploadRes); err != nil {
|
||
return nil, fmt.Errorf("解析响应失败: %v", err)
|
||
}
|
||
|
||
if uploadRes.Errcode != 0 {
|
||
return nil, fmt.Errorf("上传失败 [code=%d]: %s", uploadRes.Errcode, uploadRes.Errmsg)
|
||
}
|
||
|
||
return
|
||
}
|