go 获取微信公众号access_tokens

  • 内容
  • 评论
  • 相关

最近接触了一下微信公众号开发,刚好很久很久之前申请过一个公众号,看了下API文档,用go实现了一个简单的获取 access_token的功能。
下面的代码可以从微信服务器获取access_tokens,并保存在内存中,然后其他程序可以通过http请求获取到内存中的 access_token,超时的时候,还会自动重新从微信服务器获取新的access_tokens。

只需要配置 config.json文件即可,config.json和main.go文件处于同一目录层级,config.json格式文件配置如下:

1
2
3
4
5
6
{
    "appid":"XXX",
    "secret":"XXX",
    "token":"XXX",
    "port":"7001"
}

其中 appid,secret以及token需要在微信公众平台获取相关信息。

port 则是你使用的监听接口,即其他人通过这个接口获取access_tokens。

获取的方式是通过浏览器访问你的 url地址+/token 后缀。

运行时,输入

go run main.go config.json 即可

代码:
main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
 
package main
 
import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"
)
 
const wx_params_timestamp string = "timestamp"
const wx_params_signature string = "signature"
const wx_params_nonce string = "nonce"
const wx_params_echostr string = "echostr"
 
const wx_access_token_key string = "access_token"
const wx_access_token_time_key string = "expires_in"
 
const wx_access_token_error_code string = "errcode"
const wx_access_token_error_msg string = "errmsg"
 
//
var wx_gzh_token_str string
var wx_gzh_appid string
var wx_gzh_secret string
 
var global_access_token string
var global_access_token_time_out int64
 
type SConsConfig struct {
	Appid  string `json:"appid"`
	Secret string `json:"secret"`
	Token  string `json:"token"`
	Port   string `json:"port"`
}
 
func NewJsonStruct() *SConsConfig {
	return &SConsConfig{}
}
 
func (jst *SConsConfig) LoadConfig(fileName string, v interface{}) {
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		return
	}
	err = json.Unmarshal(data, v)
	if err != nil {
		return
	}
}
func ParseSconsConfig(fileName string) (v SConsConfig, err error) {
	JsonParse := NewJsonStruct()
	v = SConsConfig{}
	JsonParse.LoadConfig(fileName, &v)
	return v, nil
}
 
type wx_access_token_center_handler struct{}
 
func (h *wx_access_token_center_handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println("somebody require token")
 
	current_time := time.Now().Unix()
 
	if current_time > global_access_token_time_out {
		log.Println("token timetou ,require from wx...........")
		GetAccessToken(wx_gzh_appid, wx_gzh_secret)
	} else {
		log.Println("token is valid,require from local")
	}
	w.Write([]byte(global_access_token))
}
 
func ParseTokens(str string) {
	decoder := json.NewDecoder(bytes.NewBufferString(str))
	decoder.UseNumber()
	var result map[string]interface{}
	if err := decoder.Decode(&result); err != nil {
		log.Println("json parse failed,str=", str, "\nerr=", err)
		os.Exit(1)
	}
	log.Println("parse", str, "json")
 
	if _, ok := result[wx_access_token_error_code]; ok {
		log.Println("error token,code=", result[wx_access_token_error_code])
		log.Println("errmsg=", result[wx_access_token_error_msg])
	}
 
	access_token := result[wx_access_token_key]
	access_token_value, ok := access_token.(string)
	if !ok {
		log.Println("parse access_token failed,access_token=", access_token)
	}
	log.Println("access_token_value:", access_token_value)
 
	time_num := result[wx_access_token_time_key]
	time_num_value, err := time_num.(json.Number).Int64()
	if err != nil {
		log.Println("parase time_num failed,time_num=", time_num)
	}
	log.Println("time:", time_num_value)
 
	current_time := time.Now().Unix()
 
	global_access_token = access_token_value
	global_access_token_time_out = current_time + time_num_value
 
	formatTimeStr := time.Unix(global_access_token_time_out, 0).Format("2006-01-02 15:04:05")
 
	log.Println("success parse json,token will be timeout at ", global_access_token_time_out, ",", formatTimeStr)
}
 
func GetAccessToken(appid string, secret string) {
 
	params := "/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret
 
	urls := []string{"api.weixin.qq.com", "api2.weixin.qq.com", "sh.api.weixin.qq.com", "sz.api.weixin.qq.com", "hk.api.weixin.qq.com"}
 
	success := false
	for _, v := range urls {
		url := "https://" + v + params
		resp, err := http.Get(url)
		if nil != err {
			log.Println("get wx access token from "+url+" error,err=", err)
		} else {
			success = true
			log.Println("get wx access token from " + url + " success")
 
			defer resp.Body.Close()
			body, err := ioutil.ReadAll(resp.Body)
			if nil != err {
				log.Println("get wx access token error,read resp body error,err=", err)
				return
			}
			tokenstr := string(body)
			log.Println("access_token:", tokenstr)
			ParseTokens(tokenstr)
			break
		}
	}
 
	if !success {
		log.Println("get wx access error from all api")
		os.Exit(1)
	}
}
 
func InitGlobal() {
 
	wx_gzh_appid = ""
	wx_gzh_secret = ""
	wx_gzh_token_str = ""
 
	global_access_token = ""
	global_access_token_time_out = 0
}
 
func HttpTokenServer(tokenPort string) {
	http.Handle("/token", &wx_access_token_center_handler{})
	port := "0.0.0.0:" + tokenPort
	log.Println("start listen token port:", tokenPort)
	http.ListenAndServe(port, nil)
}
 
func main() {
 
	log.Println("start gzh token center")
	log.Println("param format: config.json")
 
	arg_num := len(os.Args)
 
	if arg_num < 2 {
		log.Println("please input the port")
		os.Exit(1)
	}
 
	InitGlobal()
	configFile := os.Args[1]
 
	config, err := ParseSconsConfig(configFile)
 
	if nil != err {
		log.Println("parse config error,err=", err)
		os.Exit(1)
	}
	wx_gzh_appid = config.Appid
	wx_gzh_secret = config.Secret
	wx_gzh_token_str = config.Token
 
	HttpTokenServer(config.Port)
}

原创文章,转载请注明: 转载自专注游戏开发

本文链接地址: go 获取微信公众号access_tokens

评论

0条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注