master v1.0.0
李光春 2 years ago
commit 7cdf21084d

@ -0,0 +1,17 @@
kind: pipeline
type: docker
name: clone
steps:
- name: Test
image: golang:1.18
commands:
- go env -w GO111MODULE=on
- go env -w GOPROXY=https://goproxy.cn,direct
- go test -v ./...
- name: Benchmark
image: golang:1.18
commands:
- go env -w GO111MODULE=on
- go env -w GOPROXY=https://goproxy.cn,direct
- go test -bench=. -benchmem

10
.gitignore vendored

@ -0,0 +1,10 @@
.env
.git
.svn
.idea
.vscode
*.log
goinit.sh
gomod.sh
*_test.go
/vendor/

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 李光春
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,17 @@
<h1>
<a href="https://www.dtapp.net/">Golang wechatminiprogram</a>
</h1>
📦 Golang wechatminiprogram
[comment]: <> (go)
[![godoc](https://pkg.go.dev/badge/go.dtapp.net/wechatminiprogram?status.svg)](https://pkg.go.dev/go.dtapp.net/wechatminiprogram)
[![goproxy.cn](https://goproxy.cn/stats/go.dtapp.net/wechatminiprogram/badges/download-count.svg)](https://goproxy.cn/stats/go.dtapp.net/wechatminiprogram)
[![goreportcard.com](https://goreportcard.com/badge/go.dtapp.net/wechatminiprogram)](https://goreportcard.com/report/go.dtapp.net/wechatminiprogram)
[![deps.dev](https://img.shields.io/badge/deps-go-red.svg)](https://deps.dev/go/go.dtapp.net%2Fwechatminiprogram)
#### 安装
```shell
go get -v -u go.dtapp.net/wechatminiprogram
```

@ -0,0 +1,35 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type GetCallBackIpResponse struct {
IpList []string `json:"ip_list"`
}
type GetCallBackIpResult struct {
Result GetCallBackIpResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newGetCallBackIpResult(result GetCallBackIpResponse, body []byte, http gorequest.Response, err error) *GetCallBackIpResult {
return &GetCallBackIpResult{Result: result, Body: body, Http: http, Err: err}
}
// GetCallBackIp 获取微信callback IP地址
// callback IP即微信调用开发者服务器所使用的出口IP。
// https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html#2.%20%E8%8E%B7%E5%8F%96%E5%BE%AE%E4%BF%A1callback%20IP%E5%9C%B0%E5%9D%80
func (c *Client) GetCallBackIp() *GetCallBackIpResult {
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/cgi-bin/getcallbackip?access_token=%s", c.getAccessToken()), map[string]interface{}{}, http.MethodGet)
// 定义
var response GetCallBackIpResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newGetCallBackIpResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,37 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type SubscribeMessageSendResponse struct {
Errcode int // 错误码
Errmsg string // 错误信息
}
type SubscribeMessageSendResult struct {
Result SubscribeMessageSendResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newSubscribeMessageSendResult(result SubscribeMessageSendResponse, body []byte, http gorequest.Response, err error) *SubscribeMessageSendResult {
return &SubscribeMessageSendResult{Result: result, Body: body, Http: http, Err: err}
}
// SubscribeMessageSend 发送订阅消息
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
func (c *Client) SubscribeMessageSend(notMustParams ...gorequest.Params) *SubscribeMessageSendResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/cgi-bin/message/subscribe/send?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response SubscribeMessageSendResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newSubscribeMessageSendResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,38 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type CgiBinTokenResponse struct {
AccessToken string `json:"access_token"` // 获取到的凭证
ExpiresIn int `json:"expires_in"` // 凭证有效时间单位秒。目前是7200秒之内的值
Errcode int `json:"errcode"` // 错误码
Errmsg string `json:"errmsg"` // 错误信息
}
type CgiBinTokenResult struct {
Result CgiBinTokenResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newCgiBinTokenResult(result CgiBinTokenResponse, body []byte, http gorequest.Response, err error) *CgiBinTokenResult {
return &CgiBinTokenResult{Result: result, Body: body, Http: http, Err: err}
}
// CgiBinToken
// 接口调用凭证
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
func (c *Client) CgiBinToken() *CgiBinTokenResult {
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", c.getAppId(), c.getAppSecret()), map[string]interface{}{}, http.MethodGet)
// 定义
var response CgiBinTokenResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newCgiBinTokenResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,20 @@
package wechatminiprogram
import (
"context"
"errors"
"time"
)
func (c *Client) GetAccessTokenMonitor() (string, error) {
if c.config.RedisClient.Db == nil {
return "", errors.New("驱动没有初始化")
}
result := c.GetCallBackIp()
if len(result.Result.IpList) <= 0 {
token := c.CgiBinToken()
c.config.RedisClient.Db.Set(context.Background(), c.getAccessTokenCacheKeyName(), token.Result.AccessToken, time.Second*7000)
return token.Result.AccessToken, nil
}
return c.config.AccessToken, nil
}

@ -0,0 +1,22 @@
package wechatminiprogram
import (
"fmt"
"time"
)
func (c *Client) GetAccessToken() string {
if c.config.RedisClient.Db == nil {
return c.config.AccessToken
}
newCache := c.config.RedisClient.NewSimpleStringCache(c.config.RedisClient.NewStringOperation(), time.Second*7000)
newCache.DBGetter = func() string {
token := c.CgiBinToken()
return token.Result.AccessToken
}
return newCache.GetCache(c.getAccessTokenCacheKeyName())
}
func (c *Client) getAccessTokenCacheKeyName() string {
return fmt.Sprintf("wechat_access_token:%v", c.config.AppId)
}

@ -0,0 +1,39 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type CgiBinWxaAppCreateWxaQrCodeResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
ContentType string `json:"contentType"`
Buffer interface{} `json:"buffer"`
}
type CgiBinWxaAppCreateWxaQrCodeResult struct {
Result CgiBinWxaAppCreateWxaQrCodeResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newCgiBinWxaAppCreateWxaQrCodeResult(result CgiBinWxaAppCreateWxaQrCodeResponse, body []byte, http gorequest.Response, err error) *CgiBinWxaAppCreateWxaQrCodeResult {
return &CgiBinWxaAppCreateWxaQrCodeResult{Result: result, Body: body, Http: http, Err: err}
}
// CgiBinWxaAppCreateWxaQrCode 获取小程序二维码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.createQRCode.html
func (c *Client) CgiBinWxaAppCreateWxaQrCode(notMustParams ...gorequest.Params) *CgiBinWxaAppCreateWxaQrCodeResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/cgi-bin/wxaapp/createwxaqrcode?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response CgiBinWxaAppCreateWxaQrCodeResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newCgiBinWxaAppCreateWxaQrCodeResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,65 @@
package wechatminiprogram
import (
"go.dtapp.net/dorm"
"go.dtapp.net/golog"
"go.dtapp.net/gorequest"
"gorm.io/gorm"
)
type ConfigClient struct {
AppId string // 小程序唯一凭证,即 appId
AppSecret string // 小程序唯一凭证密钥,即 appSecret
AccessToken string // 接口调用凭证
JsapiTicket string // 签名凭证
RedisClient *dorm.RedisClient // 缓存数据库
TokenDb *gorm.DB // 令牌数据库
MongoDb *dorm.MongoClient // 日志数据库
PgsqlDb *gorm.DB // 日志数据库
DatabaseName string // 库名
}
// Client 微信小程序服务
type Client struct {
client *gorequest.App // 请求客户端
log *golog.ApiClient // 日志服务
config *ConfigClient // 配置
}
func NewClient(config *ConfigClient) (*Client, error) {
var err error
c := &Client{config: config}
c.client = gorequest.NewHttp()
if c.config.PgsqlDb != nil {
c.log, err = golog.NewApiClient(
golog.WithGormClient(c.config.PgsqlDb),
golog.WithTableName(logTable),
)
if err != nil {
return nil, err
}
}
if c.config.MongoDb != nil {
c.log, err = golog.NewApiClient(
golog.WithMongoClient(c.config.MongoDb),
golog.WithDatabaseName(c.config.DatabaseName),
golog.WithCollectionName(logTable),
)
if err != nil {
return nil, err
}
}
return c, nil
}
// ConfigApp 配置
func (c *Client) ConfigApp(appId, appSecret string) *Client {
c.config.AppId = appId
c.config.AppSecret = appSecret
return c
}

@ -0,0 +1,11 @@
package wechatminiprogram
const (
apiUrl = "https://api.weixin.qq.com"
)
const (
logTable = "wechatminiprogram"
)
const Version = "1.0.0"

@ -0,0 +1,18 @@
package wechatminiprogram
func (c *Client) getAppId() string {
return c.config.AppId
}
func (c *Client) getAppSecret() string {
return c.config.AppSecret
}
func (c *Client) getAccessToken() string {
c.config.AccessToken = c.GetAccessToken()
return c.config.AccessToken
}
func (c *Client) GetAppId() string {
return c.config.AppId
}

139
go.mod

@ -0,0 +1,139 @@
module go.dtapp.net/wechatminiprogram
go 1.19
require (
go.dtapp.net/dorm v1.0.11
go.dtapp.net/golog v1.0.16
go.dtapp.net/gorequest v1.0.23
go.dtapp.net/gostorage v1.0.11
gorm.io/gorm v1.23.8
)
require (
gitee.com/chunanyong/dm v1.8.5 // indirect
gitee.com/chunanyong/zorm v1.5.9 // indirect
github.com/aliyun/aliyun-oss-go-sdk v2.2.4+incompatible // indirect
github.com/aws/aws-sdk-go v1.44.70 // indirect
github.com/baidubce/bce-sdk-go v0.9.131 // indirect
github.com/basgys/goxml2json v1.1.0 // indirect
github.com/beego/beego/v2 v2.0.5 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/clbanning/mxj v1.8.4 // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/denisenkom/go-mssqldb v0.12.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.8.1 // indirect
github.com/glebarez/go-sqlite v1.18.0 // indirect
github.com/glebarez/sqlite v1.4.6 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.0 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-redis/redis/v9 v9.0.0-beta.2 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/goccy/go-json v0.9.10 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.12.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.11.0 // indirect
github.com/jackc/pgx/v4 v4.16.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/ks3sdklib/aws-sdk-go v1.1.6 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/mailru/go-clickhouse/v2 v2.0.0 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.14 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.6.6 // indirect
github.com/mozillazg/go-httpheader v0.3.1 // indirect
github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/qiniu/go-sdk/v7 v7.13.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda // indirect
github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f // indirect
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tencentyun/cos-go-sdk-v5 v0.7.36 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/upper/db/v4 v4.5.4 // indirect
github.com/uptrace/bun v1.1.7 // indirect
github.com/uptrace/bun/dialect/mssqldialect v1.1.7 // indirect
github.com/uptrace/bun/dialect/mysqldialect v1.1.7 // indirect
github.com/uptrace/bun/dialect/pgdialect v1.1.7 // indirect
github.com/uptrace/bun/driver/pgdriver v1.1.7 // indirect
github.com/upyun/go-sdk/v3 v3.0.3 // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.dtapp.net/goip v1.0.23 // indirect
go.dtapp.net/gojson v1.0.1 // indirect
go.dtapp.net/gorandom v1.0.1 // indirect
go.dtapp.net/gostring v1.0.6 // indirect
go.dtapp.net/gotime v1.0.5 // indirect
go.dtapp.net/goxml v1.0.1 // indirect
go.mongodb.org/mongo-driver v1.10.1 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/datatypes v1.0.7 // indirect
gorm.io/driver/mysql v1.3.5 // indirect
gorm.io/driver/postgres v1.3.8 // indirect
gorm.io/driver/sqlite v1.3.6 // indirect
gorm.io/driver/sqlserver v1.3.2 // indirect
mellium.im/sasl v0.2.1 // indirect
modernc.org/b v1.0.2 // indirect
modernc.org/db v1.0.4 // indirect
modernc.org/file v1.0.3 // indirect
modernc.org/fileutil v1.1.0 // indirect
modernc.org/golex v1.0.1 // indirect
modernc.org/internal v1.0.4 // indirect
modernc.org/libc v1.16.19 // indirect
modernc.org/lldb v1.0.4 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect
modernc.org/ql v1.4.1 // indirect
modernc.org/sortutil v1.1.0 // indirect
modernc.org/sqlite v1.18.0 // indirect
modernc.org/strutil v1.1.2 // indirect
modernc.org/zappy v1.0.5 // indirect
xorm.io/builder v0.3.12 // indirect
xorm.io/xorm v1.3.1 // indirect
)

1035
go.sum

File diff suppressed because it is too large Load Diff

@ -0,0 +1,38 @@
package wechatminiprogram
import "go.dtapp.net/gorequest"
// 请求接口
func (c *Client) request(url string, params map[string]interface{}, method string) (gorequest.Response, error) {
// 创建请求
client := c.client
// 设置请求地址
client.SetUri(url)
// 设置方式
client.SetMethod(method)
// 设置格式
client.SetContentTypeJson()
// 设置参数
client.SetParams(params)
// 发起请求
request, err := client.Request()
if err != nil {
return gorequest.Response{}, err
}
// 日志
if c.config.PgsqlDb != nil {
go c.log.GormMiddleware(request)
}
if c.config.MongoDb != nil {
go c.log.MongoMiddleware(request)
}
return request, err
}

@ -0,0 +1,41 @@
package wechatminiprogram
import (
"go.dtapp.net/gorequest"
"log"
"os"
)
type SaveImgResponse struct {
Path string
Name string
}
func (c *Client) SaveImg(resp gorequest.Response, dir, saveName string) SaveImgResponse {
// 返回是二进制图片或者json错误
if resp.ResponseHeader.Get("Content-Type") == "image/jpeg" || resp.ResponseHeader.Get("Content-Type") == "image/png" {
// 保存在output目录
outputFileName := saveName
if resp.ResponseHeader.Get("Content-Type") == "image/jpeg" {
outputFileName = outputFileName + ".jpg"
} else {
outputFileName = outputFileName + ".png"
}
here:
log.Println(dir + outputFileName)
f, err := os.OpenFile(dir+outputFileName, os.O_CREATE|os.O_RDWR, 0666)
log.Println(err)
if err != nil {
os.Mkdir(dir, 0755)
goto here
}
f.Write(resp.ResponseBody)
f.Close()
return SaveImgResponse{
Path: dir + outputFileName,
Name: outputFileName,
}
}
return SaveImgResponse{}
}

@ -0,0 +1,23 @@
package wechatminiprogram
import "errors"
func (c *Client) pkcs7Unpaid(data []byte, blockSize int) ([]byte, error) {
if blockSize <= 0 {
return nil, errors.New("invalid block size")
}
if len(data)%blockSize != 0 || len(data) == 0 {
return nil, errors.New("invalid PKCS7 data")
}
d := data[len(data)-1]
n := int(d)
if n == 0 || n > len(data) {
return nil, errors.New("invalid padding on input")
}
for i := 0; i < n; i++ {
if data[len(data)-n+i] != d {
return nil, errors.New("invalid padding on input")
}
}
return data[:len(data)-n], nil
}

@ -0,0 +1,38 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type SnsJsCode2sessionResponse struct {
OpenId string `json:"openid"` // 用户唯一标识
SessionKey string `json:"session_key"` // 会话密钥
Unionid string `json:"unionid"` // 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回
Errcode string `json:"errcode"` // 错误码
Errmsg string `json:"errmsg"` // 错误信息
}
type SnsJsCode2sessionResult struct {
Result SnsJsCode2sessionResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newSnsJsCode2sessionResult(result SnsJsCode2sessionResponse, body []byte, http gorequest.Response, err error) *SnsJsCode2sessionResult {
return &SnsJsCode2sessionResult{Result: result, Body: body, Http: http, Err: err}
}
// SnsJsCode2session 登录凭证校验
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
func (c *Client) SnsJsCode2session(jsCode string) *SnsJsCode2sessionResult {
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", c.getAppId(), c.getAppSecret(), jsCode), map[string]interface{}{}, http.MethodGet)
// 定义
var response SnsJsCode2sessionResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newSnsJsCode2sessionResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,83 @@
package wechatminiprogram
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"errors"
"strings"
)
type UserInfo struct {
SessionKey string `json:"session_key"`
EncryptedData string `json:"encrypted_data"`
Iv string `json:"iv"`
}
type UserInfoResponse struct {
OpenID string `json:"openId"`
NickName string `json:"nickName"`
Gender int `json:"gender"`
City string `json:"city"`
Province string `json:"province"`
Country string `json:"country"`
AvatarUrl string `json:"avatarUrl"`
UnionId string `json:"unionId"`
Watermark struct {
AppID string `json:"appid"`
Timestamp int64 `json:"timestamp"`
} `json:"watermark"`
}
type UserInfoResult struct {
Result UserInfoResponse // 结果
Err error // 错误
}
func newUserInfoResult(result UserInfoResponse, err error) *UserInfoResult {
return &UserInfoResult{Result: result, Err: err}
}
// UserInfo 解密用户信息
func (c *Client) UserInfo(param UserInfo) *UserInfoResult {
var response UserInfoResponse
aesKey, err := base64.StdEncoding.DecodeString(param.SessionKey)
if err != nil {
return newUserInfoResult(response, err)
}
cipherText, err := base64.StdEncoding.DecodeString(param.EncryptedData)
if err != nil {
return newUserInfoResult(response, err)
}
ivBytes, err := base64.StdEncoding.DecodeString(param.Iv)
if err != nil {
return newUserInfoResult(response, err)
}
block, err := aes.NewCipher(aesKey)
if err != nil {
return newUserInfoResult(response, err)
}
mode := cipher.NewCBCDecrypter(block, ivBytes)
mode.CryptBlocks(cipherText, cipherText)
cipherText, err = c.pkcs7Unpaid(cipherText, block.BlockSize())
if err != nil {
return newUserInfoResult(response, err)
}
err = json.Unmarshal(cipherText, &response)
if err != nil {
return newUserInfoResult(response, err)
}
if response.Watermark.AppID != c.getAppId() {
return newUserInfoResult(response, errors.New("c id not match"))
}
return newUserInfoResult(response, err)
}
func (u *UserInfoResponse) UserInfoAvatarUrlReal() string {
return UserInfoAvatarUrlReal(u.AvatarUrl)
}
func UserInfoAvatarUrlReal(avatarUrl string) string {
return strings.Replace(avatarUrl, "/132", "/0", -1)
}

@ -0,0 +1,69 @@
package wechatminiprogram
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"errors"
)
type UserPhone struct {
SessionKey string `json:"session_key"`
EncryptedData string `json:"encrypted_data"`
Iv string `json:"iv"`
}
type UserPhoneResponse struct {
PhoneNumber string `json:"phoneNumber"` // 用户绑定的手机号(国外手机号会有区号)
PurePhoneNumber string `json:"purePhoneNumber"` // 没有区号的手机号
CountryCode string `json:"countryCode"` // 区号
Watermark struct {
AppID string `json:"appid"`
Timestamp int64 `json:"timestamp"`
} `json:"watermark"`
}
type UserPhoneResult struct {
Result UserPhoneResponse // 结果
Err error // 错误
}
func newUserPhoneResult(result UserPhoneResponse, err error) *UserPhoneResult {
return &UserPhoneResult{Result: result, Err: err}
}
// UserPhone 解密手机号信息
func (c *Client) UserPhone(param UserPhone) *UserPhoneResult {
var response UserPhoneResponse
aesKey, err := base64.StdEncoding.DecodeString(param.SessionKey)
if err != nil {
return newUserPhoneResult(response, err)
}
cipherText, err := base64.StdEncoding.DecodeString(param.EncryptedData)
if err != nil {
return newUserPhoneResult(response, err)
}
ivBytes, err := base64.StdEncoding.DecodeString(param.Iv)
if err != nil {
return newUserPhoneResult(response, err)
}
block, err := aes.NewCipher(aesKey)
if err != nil {
return newUserPhoneResult(response, err)
}
mode := cipher.NewCBCDecrypter(block, ivBytes)
mode.CryptBlocks(cipherText, cipherText)
cipherText, err = c.pkcs7Unpaid(cipherText, block.BlockSize())
if err != nil {
return newUserPhoneResult(response, err)
}
err = json.Unmarshal(cipherText, &response)
if err != nil {
return newUserPhoneResult(response, err)
}
if response.Watermark.AppID != c.getAppId() {
return newUserPhoneResult(response, errors.New("c id not match"))
}
return newUserPhoneResult(response, err)
}

@ -0,0 +1,68 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type BusinessGetLiveInfoResponse struct {
Errcode int `json:"errcode"` // // 错误码0代表成功1代表未创建直播间
Errmsg string `json:"errmsg"` // 错误信息
Total int `json:"total"`
RoomInfo []struct {
Name string `json:"name"` // 直播间名称
Roomid int `json:"roomid"` // 直播间ID
CoverImg string `json:"cover_img"`
ShareImg string `json:"share_img"`
LiveStatus int `json:"live_status"`
StartTime int `json:"start_time"`
EndTime int `json:"end_time"`
AnchorName string `json:"anchor_name"`
Goods []struct {
CoverImg string `json:"cover_img"`
Url string `json:"url"`
Name string `json:"name"`
Price int `json:"price"`
Price2 int `json:"price2"`
PriceType int `json:"price_type"`
GoodsId int `json:"goods_id"`
ThirdPartyAppid string `json:"third_party_appid"`
} `json:"goods"`
LiveType int `json:"live_type"`
CloseLike int `json:"close_like"`
CloseGoods int `json:"close_goods"`
CloseComment int `json:"close_comment"`
CloseKf int `json:"close_kf"`
CloseReplay int `json:"close_replay"`
IsFeedsPublic int `json:"is_feeds_public"`
CreaterOpenid string `json:"creater_openid"`
FeedsImg string `json:"feeds_img"`
} `json:"room_info"`
}
type BusinessGetLiveInfoResult struct {
Result BusinessGetLiveInfoResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newBusinessGetLiveInfoResult(result BusinessGetLiveInfoResponse, body []byte, http gorequest.Response, err error) *BusinessGetLiveInfoResult {
return &BusinessGetLiveInfoResult{Result: result, Body: body, Http: http, Err: err}
}
// BusinessGetLiveInfo 获取直播间列表
// 调用此接口获取直播间列表及直播间信息
// https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/liveplayer/studio-api.html
func (c *Client) BusinessGetLiveInfo(notMustParams ...gorequest.Params) *BusinessGetLiveInfoResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/business/getliveinfo?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response BusinessGetLiveInfoResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newBusinessGetLiveInfoResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,48 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type WxaBusinessGetUserPhoneNumberResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
PhoneInfo struct {
PhoneNumber string `json:"phoneNumber"` // 用户绑定的手机号(国外手机号会有区号)
PurePhoneNumber string `json:"purePhoneNumber"` // 没有区号的手机号
CountryCode int `json:"countryCode"` // 区号
Watermark struct {
Timestamp int `json:"timestamp"` // 用户获取手机号操作的时间戳
Appid string `json:"appid"` // 小程序appid
} `json:"watermark"`
} `json:"phone_info"`
}
type WxaBusinessGetUserPhoneNumberResult struct {
Result WxaBusinessGetUserPhoneNumberResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaBusinessGetUserPhoneNumberResult(result WxaBusinessGetUserPhoneNumberResponse, body []byte, http gorequest.Response, err error) *WxaBusinessGetUserPhoneNumberResult {
return &WxaBusinessGetUserPhoneNumberResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaBusinessGetUserPhoneNumber code换取用户手机号。 每个code只能使用一次code的有效期为5min
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/phonenumber/phonenumber.getPhoneNumber.html
func (c *Client) WxaBusinessGetUserPhoneNumber(code string) *WxaBusinessGetUserPhoneNumberResult {
// 参数
param := gorequest.NewParams()
param.Set("code", code)
params := gorequest.NewParamsWith(param)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/business/getuserphonenumber?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response WxaBusinessGetUserPhoneNumberResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaBusinessGetUserPhoneNumberResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,38 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type WxaGenerateUrlLinkResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
Openlink interface{} `json:"openlink"`
}
type WxaGenerateUrlLinkResult struct {
Result WxaGenerateUrlLinkResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaGenerateUrlLinkResult(result WxaGenerateUrlLinkResponse, body []byte, http gorequest.Response, err error) *WxaGenerateUrlLinkResult {
return &WxaGenerateUrlLinkResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaGenerateUrlLink 获取小程序 URL Link适用于短信、邮件、网页、微信内等拉起小程序的业务场景。通过该接口可以选择生成到期失效和永久有效的小程序链接有数量限制目前仅针对国内非个人主体的小程序开放
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html
func (c *Client) WxaGenerateUrlLink(notMustParams ...gorequest.Params) *WxaGenerateUrlLinkResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/generate_urllink?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response WxaGenerateUrlLinkResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaGenerateUrlLinkResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,38 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type WxaGenerateSchemeResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
UrlLink interface{} `json:"url_link"`
}
type WxaGenerateSchemeResult struct {
Result WxaGenerateSchemeResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaGenerateSchemeResult(result WxaGenerateSchemeResponse, body []byte, http gorequest.Response, err error) *WxaGenerateSchemeResult {
return &WxaGenerateSchemeResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaGenerateScheme 获取小程序 scheme 码,适用于短信、邮件、外部网页、微信内等拉起小程序的业务场景。通过该接口,可以选择生成到期失效和永久有效的小程序码,有数量限制,目前仅针对国内非个人主体的小程序开放
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html
func (c *Client) WxaGenerateScheme(notMustParams ...gorequest.Params) *WxaGenerateSchemeResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/generatescheme?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response WxaGenerateSchemeResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaGenerateSchemeResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,67 @@
package wechatminiprogram
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"go.dtapp.net/gorequest"
"go.dtapp.net/gostorage"
"net/http"
)
type WxaGetWxaCodeResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
ContentType string `json:"contentType"`
Buffer interface{} `json:"buffer"`
}
type WxaGetWxaCodeResult struct {
Result WxaGetWxaCodeResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaGetWxaCodeResult(result WxaGetWxaCodeResponse, body []byte, http gorequest.Response, err error) *WxaGetWxaCodeResult {
return &WxaGetWxaCodeResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaGetWxaCode 获取小程序码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.get.html
func (c *Client) WxaGetWxaCode(notMustParams ...gorequest.Params) *WxaGetWxaCodeResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/getwxacode?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response WxaGetWxaCodeResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaGetWxaCodeResult(response, request.ResponseBody, request, err)
}
// ErrcodeInfo 错误描述
func (resp *WxaGetWxaCodeResult) ErrcodeInfo() string {
switch resp.Result.Errcode {
case 45029:
return "生成码个数总和到达最大个数限制"
case 40097:
return "env_version 不合法"
}
return "系统繁忙"
}
// Check 检查
func (resp *WxaGetWxaCodeResult) Check() error {
// 返回是二进制图片或者json错误
if resp.Http.ResponseHeader.Get("Content-Type") == "image/jpeg" || resp.Http.ResponseHeader.Get("Content-Type") == "image/png" {
return nil
}
return errors.New("返回不是二进制图片")
}
// Update 上传
func (resp *WxaGetWxaCodeResult) Update(storage *gostorage.AliYun, filePath, fileName string) (gostorage.FileInfo, error) {
return storage.PutObject(bytes.NewReader(resp.Body), filePath, fileName)
}

@ -0,0 +1,69 @@
package wechatminiprogram
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"go.dtapp.net/gorequest"
"go.dtapp.net/gostorage"
"net/http"
)
type WxaGetWxaCodeUnLimitResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
ContentType string `json:"contentType"`
Buffer interface{} `json:"buffer"`
}
type WxaGetWxaCodeUnLimitResult struct {
Result WxaGetWxaCodeUnLimitResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaGetWxaCodeUnLimitResult(result WxaGetWxaCodeUnLimitResponse, body []byte, http gorequest.Response, err error) *WxaGetWxaCodeUnLimitResult {
return &WxaGetWxaCodeUnLimitResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaGetWxaCodeUnLimit 获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html
func (c *Client) WxaGetWxaCodeUnLimit(notMustParams ...gorequest.Params) *WxaGetWxaCodeUnLimitResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/getwxacodeunlimit?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response WxaGetWxaCodeUnLimitResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaGetWxaCodeUnLimitResult(response, request.ResponseBody, request, err)
}
// ErrcodeInfo 错误描述
func (resp *WxaGetWxaCodeUnLimitResult) ErrcodeInfo() string {
switch resp.Result.Errcode {
case 45009:
return "调用分钟频率受限(目前5000次/分钟,会调整),如需大量小程序码,建议预生成"
case 41030:
return "page 不合法(页面不存在或者小程序没有发布、根路径前加 /或者携带参数)"
case 40097:
return "env_version 不合法"
}
return "系统繁忙"
}
// Check 检查
func (resp *WxaGetWxaCodeUnLimitResult) Check() error {
// 返回是二进制图片或者json错误
if resp.Http.ResponseHeader.Get("Content-Type") == "image/jpeg" || resp.Http.ResponseHeader.Get("Content-Type") == "image/png" {
return nil
}
return errors.New("返回不是二进制图片")
}
// Update 上传
func (resp *WxaGetWxaCodeUnLimitResult) Update(storage *gostorage.AliYun, filePath, fileName string) (gostorage.FileInfo, error) {
return storage.PutObject(bytes.NewReader(resp.Body), filePath, fileName)
}

@ -0,0 +1,58 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type WxaQueryUrlLinkResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
UrlLinkInfo struct {
Appid string `json:"appid"`
Path string `json:"path"`
Query string `json:"query"`
CreateTime int `json:"create_time"`
ExpireTime int `json:"expire_time"`
EnvVersion string `json:"env_version"`
CloudBase struct {
Env string `json:"env"`
Doamin string `json:"doamin"`
Path string `json:"path"`
Query string `json:"query"`
ResourceAppid string `json:"resource_appid"`
} `json:"cloud_base"`
} `json:"url_link_info"`
UrlLinkQuota struct {
LongTimeUsed int `json:"long_time_used"`
LongTimeLimit int `json:"long_time_limit"`
} `json:"url_link_quota"`
}
type WxaQueryUrlLinkResult struct {
Result WxaQueryUrlLinkResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaQueryUrlLinkResult(result WxaQueryUrlLinkResponse, body []byte, http gorequest.Response, err error) *WxaQueryUrlLinkResult {
return &WxaQueryUrlLinkResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaQueryUrlLink 查询小程序 url_link 配置,及长期有效 quota
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.query.html
func (c *Client) WxaQueryUrlLink(urlLink string) *WxaQueryUrlLinkResult {
// 参数
param := gorequest.NewParams()
param.Set("url_link", urlLink)
params := gorequest.NewParamsWith(param)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/query_urllink?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response WxaQueryUrlLinkResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaQueryUrlLinkResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,49 @@
package wechatminiprogram
import (
"encoding/json"
"fmt"
"go.dtapp.net/gorequest"
"net/http"
)
type WxaQuerySchemeResponse struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
SchemeInfo struct {
Appid string `json:"appid"`
Path string `json:"path"`
Query string `json:"query"`
CreateTime int `json:"create_time"`
ExpireTime int `json:"expire_time"`
EnvVersion string `json:"env_version"`
} `json:"scheme_info"`
SchemeQuota struct {
LongTimeUsed int `json:"long_time_used"`
LongTimeLimit int `json:"long_time_limit"`
} `json:"scheme_quota"`
}
type WxaQuerySchemeResult struct {
Result WxaQuerySchemeResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaQuerySchemeResult(result WxaQuerySchemeResponse, body []byte, http gorequest.Response, err error) *WxaQuerySchemeResult {
return &WxaQuerySchemeResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaQueryScheme 查询小程序 scheme 码,及长期有效 quota
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.query.html
func (c *Client) WxaQueryScheme(notMustParams ...gorequest.Params) *WxaQuerySchemeResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
// 请求
request, err := c.request(fmt.Sprintf(apiUrl+"/wxa/queryscheme?access_token=%s", c.getAccessToken()), params, http.MethodPost)
// 定义
var response WxaQuerySchemeResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaQuerySchemeResult(response, request.ResponseBody, request, err)
}

@ -0,0 +1,49 @@
package wechatminiprogram
import (
"encoding/json"
"go.dtapp.net/gorequest"
"net/http"
)
type WxaApiFeedbackListResponse struct {
List []struct {
RecordId int `json:"record_id"`
CreateTime int `json:"create_time"`
Content string `json:"content"`
Phone string `json:"phone"`
Openid string `json:"openid"`
Nickname string `json:"nickname"`
HeadUrl string `json:"head_url"`
Type int `json:"type"`
MediaIds []string `json:"mediaIds"`
} `json:"list"`
TotalNum int `json:"total_num"`
Errcode int `json:"errcode"`
RpcCount int `json:"__rpcCount"`
}
type WxaApiFeedbackListResult struct {
Result WxaApiFeedbackListResponse // 结果
Body []byte // 内容
Http gorequest.Response // 请求
Err error // 错误
}
func newWxaApiFeedbackListResult(result WxaApiFeedbackListResponse, body []byte, http gorequest.Response, err error) *WxaApiFeedbackListResult {
return &WxaApiFeedbackListResult{Result: result, Body: body, Http: http, Err: err}
}
// WxaApiFeedbackList 获取用户反馈列表
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/operation/operation.getFeedback.html
func (c *Client) WxaApiFeedbackList(notMustParams ...gorequest.Params) *WxaApiFeedbackListResult {
// 参数
params := gorequest.NewParamsWith(notMustParams...)
params.Set("access_token", c.getAccessToken())
// 请求
request, err := c.request(apiUrl+"/wxaapi/feedback/list", params, http.MethodGet)
// 定义
var response WxaApiFeedbackListResponse
err = json.Unmarshal(request.ResponseBody, &response)
return newWxaApiFeedbackListResult(response, request.ResponseBody, request, err)
}
Loading…
Cancel
Save