|
|
@@ -0,0 +1,127 @@
|
|
|
+package generic
|
|
|
+
|
|
|
+import (
|
|
|
+ context2 "context"
|
|
|
+ "net/url"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ "github.com/silenceper/wechat/v2/miniprogram/context"
|
|
|
+ "github.com/silenceper/wechat/v2/util"
|
|
|
+)
|
|
|
+
|
|
|
+// defaultBaseURL 微信 API 默认基础地址
|
|
|
+const defaultBaseURL = "https://api.weixin.qq.com"
|
|
|
+
|
|
|
+// Generic 通用 API 调用,用于访问 SDK 尚未封装的小程序接口。
|
|
|
+// 支持自定义 path、query 参数、request body 以及 response 结构体。
|
|
|
+type Generic struct {
|
|
|
+ *context.Context
|
|
|
+}
|
|
|
+
|
|
|
+// NewGeneric init
|
|
|
+func NewGeneric(ctx *context.Context) *Generic {
|
|
|
+ return &Generic{ctx}
|
|
|
+}
|
|
|
+
|
|
|
+// BuildURL 构建完整请求 URL。
|
|
|
+// path 支持相对路径(如 "/intp/xxx")或完整 URL(如 "https://api.weixin.qq.com/intp/xxx")。
|
|
|
+// query 为额外的 URL 查询参数,可为 nil;access_token 会自动追加(若 query 中已包含则不重复追加)。
|
|
|
+func (g *Generic) BuildURL(path string, query url.Values) (string, error) {
|
|
|
+ return g.BuildURLContext(context2.Background(), path, query)
|
|
|
+}
|
|
|
+
|
|
|
+// BuildURLContext 构建完整请求 URL(带 context)
|
|
|
+func (g *Generic) BuildURLContext(ctx context2.Context, path string, query url.Values) (string, error) {
|
|
|
+ var baseURL string
|
|
|
+ switch {
|
|
|
+ case strings.HasPrefix(path, "http://"), strings.HasPrefix(path, "https://"):
|
|
|
+ baseURL = path
|
|
|
+ case strings.HasPrefix(path, "/"):
|
|
|
+ baseURL = defaultBaseURL + path
|
|
|
+ default:
|
|
|
+ baseURL = defaultBaseURL + "/" + path
|
|
|
+ }
|
|
|
+
|
|
|
+ // 克隆 query,避免修改调用方原始值
|
|
|
+ q := make(url.Values, len(query)+1)
|
|
|
+ for k, v := range query {
|
|
|
+ q[k] = v
|
|
|
+ }
|
|
|
+
|
|
|
+ // 自动追加 access_token
|
|
|
+ if q.Get("access_token") == "" {
|
|
|
+ accessToken, err := g.GetAccessTokenContext(ctx)
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ q.Set("access_token", accessToken)
|
|
|
+ }
|
|
|
+
|
|
|
+ sep := "?"
|
|
|
+ if strings.Contains(baseURL, "?") {
|
|
|
+ sep = "&"
|
|
|
+ }
|
|
|
+ return baseURL + sep + q.Encode(), nil
|
|
|
+}
|
|
|
+
|
|
|
+// Get 发送 GET 请求,返回原始响应字节。
|
|
|
+// 使用 util.DecodeWithError 可将响应解码到自定义结构体。
|
|
|
+func (g *Generic) Get(path string, query url.Values) (response []byte, err error) {
|
|
|
+ return g.GetContext(context2.Background(), path, query)
|
|
|
+}
|
|
|
+
|
|
|
+// GetContext 发送 GET 请求(带 context),返回原始响应字节
|
|
|
+func (g *Generic) GetContext(ctx context2.Context, path string, query url.Values) (response []byte, err error) {
|
|
|
+ var uri string
|
|
|
+ if uri, err = g.BuildURLContext(ctx, path, query); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return util.HTTPGetContext(ctx, uri)
|
|
|
+}
|
|
|
+
|
|
|
+// PostJSON 发送 POST 请求(JSON body),返回原始响应字节。
|
|
|
+// body 可为 nil(无请求体);使用 util.DecodeWithError 可将响应解码到自定义结构体。
|
|
|
+func (g *Generic) PostJSON(path string, query url.Values, body interface{}) (response []byte, err error) {
|
|
|
+ return g.PostJSONContext(context2.Background(), path, query, body)
|
|
|
+}
|
|
|
+
|
|
|
+// PostJSONContext 发送 POST 请求(JSON body,带 context),返回原始响应字节
|
|
|
+func (g *Generic) PostJSONContext(ctx context2.Context, path string, query url.Values, body interface{}) (response []byte, err error) {
|
|
|
+ var uri string
|
|
|
+ if uri, err = g.BuildURLContext(ctx, path, query); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return util.PostJSONContext(ctx, uri, body)
|
|
|
+}
|
|
|
+
|
|
|
+// GetDecode 发送 GET 请求并将响应解码到 resp。
|
|
|
+// resp 应为指向结构体的指针,结构体中可嵌入 util.CommonError 以自动校验错误码。
|
|
|
+// apiName 用于错误信息标识。
|
|
|
+func (g *Generic) GetDecode(path string, query url.Values, resp interface{}, apiName string) (err error) {
|
|
|
+ return g.GetDecodeContext(context2.Background(), path, query, resp, apiName)
|
|
|
+}
|
|
|
+
|
|
|
+// GetDecodeContext 发送 GET 请求并将响应解码到 resp(带 context)
|
|
|
+func (g *Generic) GetDecodeContext(ctx context2.Context, path string, query url.Values, resp interface{}, apiName string) (err error) {
|
|
|
+ var response []byte
|
|
|
+ if response, err = g.GetContext(ctx, path, query); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return util.DecodeWithError(response, resp, apiName)
|
|
|
+}
|
|
|
+
|
|
|
+// PostJSONDecode 发送 POST 请求(JSON body)并将响应解码到 resp。
|
|
|
+// resp 应为指向结构体的指针,结构体中可嵌入 util.CommonError 以自动校验错误码。
|
|
|
+// apiName 用于错误信息标识。
|
|
|
+func (g *Generic) PostJSONDecode(path string, query url.Values, body, resp interface{}, apiName string) (err error) {
|
|
|
+ return g.PostJSONDecodeContext(context2.Background(), path, query, body, resp, apiName)
|
|
|
+}
|
|
|
+
|
|
|
+// PostJSONDecodeContext 发送 POST 请求(JSON body)并将响应解码到 resp(带 context)
|
|
|
+func (g *Generic) PostJSONDecodeContext(ctx context2.Context, path string, query url.Values, body, resp interface{}, apiName string) (err error) {
|
|
|
+ var response []byte
|
|
|
+ if response, err = g.PostJSONContext(ctx, path, query, body); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return util.DecodeWithError(response, resp, apiName)
|
|
|
+}
|