微信公众号获取关注列表
This commit is contained in:
commit
cf845c9cd3
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
9
.idea/development-kit-sdk.iml
Normal file
9
.idea/development-kit-sdk.iml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/development-kit-sdk.iml" filepath="$PROJECT_DIR$/.idea/development-kit-sdk.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
3
go.mod
Normal file
3
go.mod
Normal file
@ -0,0 +1,3 @@
|
||||
module git.valavala.com/vala/development-kit-sdk
|
||||
|
||||
go 1.24.9
|
||||
1
pre_commit.sh
Normal file
1
pre_commit.sh
Normal file
@ -0,0 +1 @@
|
||||
go build ./... && go mod tidy
|
||||
42
utils/http.go
Normal file
42
utils/http.go
Normal file
@ -0,0 +1,42 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HttpRequest 发送 HTTP 请求
|
||||
func HttpRequest(method, url string, headers map[string]string, body []byte) ([]byte, error) {
|
||||
client := &http.Client{
|
||||
Timeout: 30 * time.Second, // 设置超时时间
|
||||
}
|
||||
|
||||
// 创建请求
|
||||
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
for key, value := range headers {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// 检查响应状态码
|
||||
rBody, err := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(rBody))
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
return rBody, err
|
||||
}
|
||||
68
wechat-sdk/access-token/access_token.go
Normal file
68
wechat-sdk/access-token/access_token.go
Normal file
@ -0,0 +1,68 @@
|
||||
package access_token
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.valavala.com/vala/development-kit-sdk/utils"
|
||||
"git.valavala.com/vala/development-kit-sdk/wechat-sdk/structs"
|
||||
)
|
||||
|
||||
var wechatStableAccessToken []*structs.WechatStableAccessToken
|
||||
|
||||
type wechatStableAccessTokenMgr struct {
|
||||
}
|
||||
|
||||
func NewWechatStableAccessTokenMgr() *wechatStableAccessTokenMgr {
|
||||
return &wechatStableAccessTokenMgr{}
|
||||
}
|
||||
|
||||
func (m *wechatStableAccessTokenMgr) GetStableAccessToken(appConf *structs.WechatConf) (string, error) {
|
||||
if appConf == nil {
|
||||
return "", errors.New("conf is empty")
|
||||
}
|
||||
|
||||
for i := range wechatStableAccessToken {
|
||||
if wechatStableAccessToken[i].Appid == appConf.AppId {
|
||||
if wechatStableAccessToken[i].AccessTokenExpiresAt > time.Now().Unix() && wechatStableAccessToken[i].AccessToken != "" {
|
||||
return wechatStableAccessToken[i].AccessToken, nil
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
url := "https://api.weixin.qq.com/cgi-bin/stable_token"
|
||||
params := map[string]string{
|
||||
"grant_type": "client_credential",
|
||||
"appid": appConf.AppId,
|
||||
"secret": appConf.AppSecret,
|
||||
}
|
||||
body, _ := json.Marshal(params)
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp, err := utils.HttpRequest(http.MethodPost, url, header, body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
thisToken := &structs.WechatStableAccessToken{}
|
||||
_ = json.Unmarshal(resp, thisToken)
|
||||
thisToken.AccessTokenExpiresAt = time.Now().Unix() + int64(thisToken.ExpiresIn)
|
||||
thisToken.Appid = appConf.AppId
|
||||
if thisToken.AccessToken == "" {
|
||||
return "", errors.New(appConf.AppId + " access_token is empty")
|
||||
}
|
||||
|
||||
var newTokens []*structs.WechatStableAccessToken
|
||||
for i := range wechatStableAccessToken {
|
||||
if wechatStableAccessToken[i].Appid == appConf.AppId {
|
||||
newTokens = append(newTokens, thisToken)
|
||||
continue
|
||||
}
|
||||
newTokens = append(newTokens, wechatStableAccessToken[i])
|
||||
}
|
||||
wechatStableAccessToken = newTokens
|
||||
|
||||
return thisToken.AccessToken, nil
|
||||
}
|
||||
43
wechat-sdk/public-platform/fans.go
Normal file
43
wechat-sdk/public-platform/fans.go
Normal file
@ -0,0 +1,43 @@
|
||||
package public_platform
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"git.valavala.com/vala/development-kit-sdk/utils"
|
||||
access_token "git.valavala.com/vala/development-kit-sdk/wechat-sdk/access-token"
|
||||
"git.valavala.com/vala/development-kit-sdk/wechat-sdk/structs"
|
||||
)
|
||||
|
||||
type PublicPlatform struct {
|
||||
}
|
||||
|
||||
func NewWechatPublicPlatform() *PublicPlatform {
|
||||
return &PublicPlatform{}
|
||||
}
|
||||
|
||||
// GetFans 获取公众号的关注列表
|
||||
// https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=OPENID
|
||||
func (p *PublicPlatform) GetFans(wechatConf *structs.WechatConf, nextOpenid string) (*structs.WechatPublicPlatformFansResp, error) {
|
||||
mgr := access_token.NewWechatStableAccessTokenMgr()
|
||||
accessToken, err := mgr.GetStableAccessToken(wechatConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
url := "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken + "&next_openid=" + nextOpenid
|
||||
|
||||
header := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp, err := utils.HttpRequest(http.MethodGet, url, header, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wechatPublicPlatformFansResp := &structs.WechatPublicPlatformFansResp{}
|
||||
_ = json.Unmarshal(resp, wechatPublicPlatformFansResp)
|
||||
if wechatPublicPlatformFansResp.Errcode != 0 {
|
||||
return nil, errors.New(wechatPublicPlatformFansResp.Errmsg)
|
||||
}
|
||||
return wechatPublicPlatformFansResp, nil
|
||||
}
|
||||
21
wechat-sdk/structs/common.go
Normal file
21
wechat-sdk/structs/common.go
Normal file
@ -0,0 +1,21 @@
|
||||
package structs
|
||||
|
||||
type WechatConf struct {
|
||||
AppId string `json:"appId"`
|
||||
AppName string `json:"appName"`
|
||||
AppSecret string `json:"appSecret"`
|
||||
MsgToken string `json:"msgToken"`
|
||||
MsgAesKey string `json:"msgAesKey"`
|
||||
}
|
||||
|
||||
type WechatStableAccessToken struct {
|
||||
Appid string `json:"appid"`
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
AccessTokenExpiresAt int64 `json:"access_token_expires_at"`
|
||||
}
|
||||
|
||||
type WechatCommonResp struct {
|
||||
Errcode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
}
|
||||
20
wechat-sdk/structs/public_platform_fans.go
Normal file
20
wechat-sdk/structs/public_platform_fans.go
Normal file
@ -0,0 +1,20 @@
|
||||
package structs
|
||||
|
||||
/*
|
||||
WechatPublicPlatformFansResp
|
||||
|
||||
一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。
|
||||
最后一次返回时next_openid可能为空表示列表结束。
|
||||
|
||||
接口信息:https://developers.weixin.qq.com/doc/subscription/api/usermanage/userinfo/api_getfans.html
|
||||
*/
|
||||
|
||||
type WechatPublicPlatformFansResp struct {
|
||||
WechatCommonResp
|
||||
Total int `json:"total"` //关注该公众账号的总用户数
|
||||
Count int `json:"count"` //拉取的OPENID个数,最大值为10000
|
||||
Data struct { //列表数据,OPENID的列表
|
||||
Openid []string `json:"openid"` //用户唯一ID
|
||||
}
|
||||
NextOpenid string `json:"next_openid"` //拉取列表后一个用户的OPENID
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user