go 获取微信公众号access_tokens


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

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

{
    "appid":"XXX",
    "secret":"XXX",
    "token":"XXX",
    "port":"7001"
}

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

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

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

运行时,输入

go run main.go config.json 即可

代码:
main.go


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)
}



发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注