diff --git a/miniprogram/content/content.go b/miniprogram/content/content.go index d53f2db1e..f3f1b784c 100644 --- a/miniprogram/content/content.go +++ b/miniprogram/content/content.go @@ -53,9 +53,12 @@ func (content *Content) CheckImage(media string) error { if err != nil { return err } + var directory = media response, err := util.PostFile( "media", - media, + nil, + "", + directory, fmt.Sprintf(checkImageURL, accessToken), ) if err != nil { diff --git a/miniprogram/security/security.go b/miniprogram/security/security.go index 3e979a513..0f484b0cc 100644 --- a/miniprogram/security/security.go +++ b/miniprogram/security/security.go @@ -95,14 +95,14 @@ func (security *Security) MediaCheckAsync(in *MediaCheckAsyncRequest) (traceID s // https://developers.weixin.qq.com/miniprogram/dev/framework/security.imgSecCheck.html // Deprecated // 在2021年9月1日停止更新。建议使用 MediaCheckAsync -func (security *Security) ImageCheckV1(filename string) (err error) { +func (security *Security) ImageCheckV1(directory string) (err error) { accessToken, err := security.GetAccessToken() if err != nil { return } uri := fmt.Sprintf(imageCheckURL, accessToken) - response, err := util.PostFile("media", filename, uri) + response, err := util.PostFile("media", nil, "", directory, uri) if err != nil { return } diff --git a/officialaccount/customerservice/manager.go b/officialaccount/customerservice/manager.go index 973a86c2f..9f92f2bc2 100644 --- a/officialaccount/customerservice/manager.go +++ b/officialaccount/customerservice/manager.go @@ -204,7 +204,7 @@ func (csm *Manager) InviteBind(kfAccount, inviteWX string) (err error) { } // UploadHeadImg 上传客服头像 -func (csm *Manager) UploadHeadImg(kfAccount, fileName string) (err error) { +func (csm *Manager) UploadHeadImg(kfAccount, directory string) (err error) { var accessToken string accessToken, err = csm.GetAccessToken() if err != nil { @@ -212,7 +212,7 @@ func (csm *Manager) UploadHeadImg(kfAccount, fileName string) (err error) { } uri := fmt.Sprintf("%s?access_token=%s&kf_account=%s", customerServiceUploadHeadImg, accessToken, kfAccount) var response []byte - response, err = util.PostFile("media", fileName, uri) + response, err = util.PostFile("media", nil, "", directory, uri) if err != nil { return } diff --git a/officialaccount/material/material.go b/officialaccount/material/material.go index d8a43b94a..716fd15f7 100644 --- a/officialaccount/material/material.go +++ b/officialaccount/material/material.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "path" "github.com/silenceper/wechat/v2/officialaccount/context" "github.com/silenceper/wechat/v2/util" @@ -163,7 +164,7 @@ type resAddMaterial struct { } // AddMaterialFromReader 上传永久性素材(处理视频需要单独上传),从 io.Reader 中读取 -func (material *Material) AddMaterialFromReader(mediaType MediaType, filename string, reader io.Reader) (mediaID string, url string, err error) { +func (material *Material) AddMaterialFromReader(mediaType MediaType, directory string, reader io.Reader) (mediaID string, url string, err error) { if mediaType == MediaTypeVideo { err = errors.New("永久视频素材上传使用 AddVideo 方法") return @@ -176,7 +177,7 @@ func (material *Material) AddMaterialFromReader(mediaType MediaType, filename st uri := fmt.Sprintf("%s?access_token=%s&type=%s", addMaterialURL, accessToken, mediaType) var response []byte - response, err = util.PostFileFromReader("media", filename, uri, reader) + response, err = util.PostFileFromReader("media", directory, uri, reader) if err != nil { return } @@ -195,14 +196,14 @@ func (material *Material) AddMaterialFromReader(mediaType MediaType, filename st } // AddMaterial 上传永久性素材(处理视频需要单独上传) -func (material *Material) AddMaterial(mediaType MediaType, filename string) (mediaID string, url string, err error) { - f, err := os.Open(filename) +func (material *Material) AddMaterial(mediaType MediaType, directory string) (mediaID string, url string, err error) { + f, err := os.Open(directory) if err != nil { return } defer func() { _ = f.Close() }() - return material.AddMaterialFromReader(mediaType, filename, f) + return material.AddMaterialFromReader(mediaType, directory, f) } type reqVideo struct { @@ -211,7 +212,7 @@ type reqVideo struct { } // AddVideoFromReader 永久视频素材文件上传,从 io.Reader 中读取 -func (material *Material) AddVideoFromReader(filename, title, introduction string, reader io.Reader) (mediaID string, url string, err error) { +func (material *Material) AddVideoFromReader(directory, title, introduction string, reader io.Reader) (mediaID string, url string, err error) { var accessToken string accessToken, err = material.GetAccessToken() if err != nil { @@ -229,12 +230,14 @@ func (material *Material) AddVideoFromReader(filename, title, introduction strin if err != nil { return } - + // 获取文件名 + fileName := path.Base(directory) fields := []util.MultipartFormField{ { IsFile: true, Fieldname: "media", - Filename: filename, + Filename: fileName, + Directory: directory, FileReader: reader, }, { @@ -265,14 +268,14 @@ func (material *Material) AddVideoFromReader(filename, title, introduction strin } // AddVideo 永久视频素材文件上传 -func (material *Material) AddVideo(filename, title, introduction string) (mediaID string, url string, err error) { - f, err := os.Open(filename) +func (material *Material) AddVideo(directory, title, introduction string) (mediaID string, url string, err error) { + f, err := os.Open(directory) if err != nil { return "", "", err } defer func() { _ = f.Close() }() - return material.AddVideoFromReader(filename, title, introduction, f) + return material.AddVideoFromReader(directory, title, introduction, f) } type reqDeleteMaterial struct { diff --git a/officialaccount/material/media.go b/officialaccount/material/media.go index 316758fb4..1d560e0ba 100644 --- a/officialaccount/material/media.go +++ b/officialaccount/material/media.go @@ -3,6 +3,9 @@ package material import ( "encoding/json" "fmt" + "io" + "net/http" + "strings" "github.com/silenceper/wechat/v2/util" ) @@ -38,16 +41,32 @@ type Media struct { } // MediaUpload 临时素材上传 -func (material *Material) MediaUpload(mediaType MediaType, filename string) (media Media, err error) { +func (material *Material) MediaUpload(mediaType MediaType, url string) (media Media, err error) { var accessToken string - accessToken, err = material.GetAccessToken() - if err != nil { + if accessToken, err = material.GetAccessToken(); err != nil { return } - uri := fmt.Sprintf("%s?access_token=%s&type=%s", mediaUploadURL, accessToken, mediaType) + // 使用strings.LastIndex函数找到最后一个斜杠的位置 + lastSlashIndex := strings.LastIndex(url, "/") + // 从最后一个斜杠的位置截取到最后,获取文件名 + filename := url[lastSlashIndex+1:] + // 获取资源 + resp, err := http.Get(url) + if err != nil { + err = fmt.Errorf("get image error: %v", err) + return + } + // 读取响应到内存 + var imageData []byte + imageData, err = io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + err = fmt.Errorf("read image error: %v", err) + return + } var response []byte - response, err = util.PostFile("media", filename, uri) + response, err = util.PostFile("media", imageData, filename, "", uri) if err != nil { return } @@ -56,7 +75,7 @@ func (material *Material) MediaUpload(mediaType MediaType, filename string) (med return } if media.ErrCode != 0 { - err = fmt.Errorf("MediaUpload error : errcode=%v , errmsg=%v", media.ErrCode, media.ErrMsg) + err = fmt.Errorf("MediaUpload error : errcode=%v, errmsg=%v", media.ErrCode, media.ErrMsg) return } return @@ -91,7 +110,8 @@ func (material *Material) ImageUpload(filename string) (url string, err error) { uri := fmt.Sprintf("%s?access_token=%s", mediaUploadImageURL, accessToken) var response []byte - response, err = util.PostFile("media", filename, uri) + var directory = filename + response, err = util.PostFile("media", nil, "", directory, uri) if err != nil { return } diff --git a/officialaccount/message/template.go b/officialaccount/message/template.go index 17176354b..1c657ea92 100644 --- a/officialaccount/message/template.go +++ b/officialaccount/message/template.go @@ -61,15 +61,15 @@ func (tpl *Template) Send(msg *TemplateMessage) (msgID int64, err error) { if err != nil { return } - var ( - uri = fmt.Sprintf("%s?access_token=%s", templateSendURL, accessToken) - response []byte - ) - if response, err = util.PostJSON(uri, msg); err != nil { + uri := fmt.Sprintf("%s?access_token=%s", templateSendURL, accessToken) + var response []byte + response, err = util.PostJSON(uri, msg) + if err != nil { return } var result resTemplateSend - if err = json.Unmarshal(response, &result); err != nil { + err = json.Unmarshal(response, &result) + if err != nil { return } if result.ErrCode != 0 { @@ -103,11 +103,10 @@ func (tpl *Template) List() (templateList []*TemplateItem, err error) { if err != nil { return } - var ( - uri = fmt.Sprintf("%s?access_token=%s", templateListURL, accessToken) - response []byte - ) - if response, err = util.HTTPGet(uri); err != nil { + uri := fmt.Sprintf("%s?access_token=%s", templateListURL, accessToken) + var response []byte + response, err = util.HTTPGet(uri) + if err != nil { return } var res resTemplateList @@ -122,23 +121,22 @@ type resTemplateAdd struct { } // Add 添加模板. -func (tpl *Template) Add(shortID string, keyNameList []string) (templateID string, err error) { +func (tpl *Template) Add(shortID string) (templateID string, err error) { var accessToken string accessToken, err = tpl.GetAccessToken() if err != nil { return } - var ( - msg = struct { - ShortID string `json:"template_id_short"` - KeyNameList []string `json:"keyword_name_list"` - }{ShortID: shortID, KeyNameList: keyNameList} - uri = fmt.Sprintf("%s?access_token=%s", templateAddURL, accessToken) - response []byte - ) - if response, err = util.PostJSON(uri, msg); err != nil { + var msg = struct { + ShortID string `json:"template_id_short"` + }{ShortID: shortID} + uri := fmt.Sprintf("%s?access_token=%s", templateAddURL, accessToken) + var response []byte + response, err = util.PostJSON(uri, msg) + if err != nil { return } + var result resTemplateAdd err = util.DecodeWithError(response, &result, "AddTemplate") return result.TemplateID, err @@ -151,14 +149,14 @@ func (tpl *Template) Delete(templateID string) (err error) { if err != nil { return } - var ( - msg = struct { - TemplateID string `json:"template_id"` - }{TemplateID: templateID} - uri = fmt.Sprintf("%s?access_token=%s", templateDelURL, accessToken) - response []byte - ) - if response, err = util.PostJSON(uri, msg); err != nil { + var msg = struct { + TemplateID string `json:"template_id"` + }{TemplateID: templateID} + + uri := fmt.Sprintf("%s?access_token=%s", templateDelURL, accessToken) + var response []byte + response, err = util.PostJSON(uri, msg) + if err != nil { return } return util.DecodeWithCommonError(response, "DeleteTemplate") diff --git a/util/http.go b/util/http.go index b9b4b004b..7d5b4f373 100644 --- a/util/http.go +++ b/util/http.go @@ -13,6 +13,7 @@ import ( "mime/multipart" "net/http" "os" + "path" "golang.org/x/crypto/pkcs12" ) @@ -146,25 +147,43 @@ func PostJSONWithRespContentType(uri string, obj interface{}) ([]byte, string, e return responseData, contentType, err } -// PostFile 上传文件 -func PostFile(fieldName, filename, uri string) ([]byte, error) { +// PostFile 支持流或文件形式上传 +func PostFile(fieldName string, data []byte, fileName string, directory string, uri string) ([]byte, error) { + var fileContent []byte + var isFile bool + // 判断 + if len(data) == 0 && directory != "" { + fileName = path.Base(directory) + isFile = true + } else if len(data) > 0 && fileName != "" { + fileContent = data + isFile = false + } else { + return nil, fmt.Errorf("error parameter required streamdata=%v and filename=%v or only directory=%v", data, fileName, directory) + } + fields := []MultipartFormField{ { - IsFile: true, + IsFile: isFile, Fieldname: fieldName, - Filename: filename, + Value: fileContent, + Filename: fileName, + Directory: directory, }, } return PostMultipartForm(fields, uri) } // PostFileFromReader 上传文件,从 io.Reader 中读取 -func PostFileFromReader(filedName, fileName, uri string, reader io.Reader) ([]byte, error) { +func PostFileFromReader(filedName, directory, uri string, reader io.Reader) ([]byte, error) { + // 获取文件名 + fileName := path.Base(directory) fields := []MultipartFormField{ { IsFile: true, Fieldname: filedName, Filename: fileName, + Directory: directory, FileReader: reader, }, } @@ -177,6 +196,7 @@ type MultipartFormField struct { Fieldname string Value []byte Filename string + Directory string FileReader io.Reader } @@ -197,7 +217,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte } if field.FileReader == nil { - fh, e := os.Open(field.Filename) + fh, e := os.Open(field.Directory) if e != nil { err = fmt.Errorf("error opening file , err=%v", e) return @@ -213,7 +233,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte } } } else { - partWriter, e := bodyWriter.CreateFormField(field.Fieldname) + partWriter, e := bodyWriter.CreateFormFile(field.Fieldname, field.Filename) if e != nil { err = e return diff --git a/work/material/media.go b/work/material/media.go index b32785a5c..9b0ea9fa0 100644 --- a/work/material/media.go +++ b/work/material/media.go @@ -48,7 +48,8 @@ func (r *Client) UploadImg(filename string) (*UploadImgResponse, error) { return nil, err } var response []byte - if response, err = util.PostFile("media", filename, fmt.Sprintf(uploadImgURL, accessToken)); err != nil { + var directory = filename + if response, err = util.PostFile("media", nil, "", directory, fmt.Sprintf(uploadImgURL, accessToken)); err != nil { return nil, err } result := &UploadImgResponse{} @@ -68,7 +69,8 @@ func (r *Client) UploadTempFile(filename string, mediaType string) (*UploadTempF return nil, err } var response []byte - if response, err = util.PostFile("media", filename, fmt.Sprintf(uploadTempFile, accessToken, mediaType)); err != nil { + var directory = filename + if response, err = util.PostFile("media", nil, "", directory, fmt.Sprintf(uploadTempFile, accessToken, mediaType)); err != nil { return nil, err } result := &UploadTempFileResponse{} @@ -89,7 +91,8 @@ func (r *Client) UploadAttachment(filename string, mediaType string, attachmentT return nil, err } var response []byte - if response, err = util.PostFile("media", filename, fmt.Sprintf(uploadAttachment, accessToken, mediaType, attachmentType)); err != nil { + var directory = filename + if response, err = util.PostFile("media", nil, "", directory, fmt.Sprintf(uploadAttachment, accessToken, mediaType, attachmentType)); err != nil { return nil, err } result := &UploadAttachmentResponse{}