wechat icon indicating copy to clipboard operation
wechat copied to clipboard

微信access_token中控服务器

Open AnsonCode opened this issue 6 years ago • 7 comments

假如我的应用需要对接多个微信公众号,且需要在不重启服务器的情况下,新增或更改公众号的appid等信息,那么公众号的【access_token中控服务器】的tokenUpdateDaemon进程如何销毁呢?

AnsonCode avatar Apr 04 '19 08:04 AnsonCode

可以考虑自己重写一部分信息。在切换的时候,更改appid。

XuHaoIgeneral avatar Apr 18 '19 01:04 XuHaoIgeneral

我重新实现了中控服务器接口,用缓存存储token,但是没做并发安全。 `package wx import ( "time" "fmt" // "sync" "net/http" "net/url" "github.com/chanxuehong/wechat/util" "github.com/chanxuehong/wechat/mp/core" "encoding/json" ) type Cache interface{ Get(k string) (interface{}, bool) SetDefault(k string, x interface{}) Set(k string, x interface{}, d time.Duration) } // DefaultAccessTokenServer 实现了 AccessTokenServer 接口. // 用于多进程环境. type DefaultAccessTokenServer struct { appId string appSecret string httpClient *http.Client cache Cache // accessTokenLock *sync.RWMutex // 读写锁 同一个AppID一个 }

// NewDefaultAccessTokenServer 创建一个新的 DefaultAccessTokenServer, 如果 httpClient == nil 则默认使用 util.DefaultHttpClient. func NewDefaultAccessTokenServer(appId, appSecret string, c Cache) (srv *DefaultAccessTokenServer) {

srv = &DefaultAccessTokenServer{
	appId:                    url.QueryEscape(appId),
	appSecret:                url.QueryEscape(appSecret),
	httpClient:               util.DefaultHttpClient,
	cache:						c,
}

return

}

func (srv *DefaultAccessTokenServer) IID01332E16DF5011E5A9D5A4DB30FED8E1() {}

func (srv *DefaultAccessTokenServer) Token() (token string, err error) { // srv.accessTokenLock.Lock() // defer srv.accessTokenLock.Unlock()

accessTokenCacheKey := fmt.Sprintf("access_token_%s", srv.appId)
val,ok:= srv.cache.Get(accessTokenCacheKey)
if ok {
	token = val.(string)
	return
}

//从微信服务器获取
var resAccessToken *accessToken
resAccessToken, err = srv.GetAccessTokenFromServer()
if err != nil {
	return
}
expires := resAccessToken.ExpiresIn - 1500
srv.cache.Set(accessTokenCacheKey, resAccessToken.Token, time.Duration(expires)*time.Second)

token = resAccessToken.Token
return 

}

type accessToken struct { Token string json:"access_token" ExpiresIn int64 json:"expires_in" }

// updateToken 从微信服务器获取新的 access_token 并存入缓存, 同时返回该 access_token. func (srv *DefaultAccessTokenServer) GetAccessTokenFromServer() (token *accessToken, err error) { url := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + srv.appId + "&secret=" + srv.appSecret // api.DebugPrintGetRequest(url) httpResp, err := srv.httpClient.Get(url) if err != nil { // atomic.StorePointer(&srv.tokenCache, nil) return } defer httpResp.Body.Close()

if httpResp.StatusCode != http.StatusOK {
	// atomic.StorePointer(&srv.tokenCache, nil)
	err = fmt.Errorf("http.Status: %s", httpResp.Status)
	return
}

var result struct {
	core.Error
	accessToken
}

if err = json.NewDecoder(httpResp.Body).Decode(&result); err != nil {
	// atomic.StorePointer(&srv.tokenCache, nil)
	return
}
if result.ErrCode != core.ErrCodeOK {
	// atomic.StorePointer(&srv.tokenCache, nil)
	err = &result.Error
	return
}

tokenCopy := result.accessToken
// atomic.StorePointer(&srv.tokenCache, unsafe.Pointer(&tokenCopy))
token = &tokenCopy
return

}

func (srv *DefaultAccessTokenServer)RefreshToken(currentToken string) (token string, err error){

return "",nil

}`

AnsonCode avatar Apr 18 '19 03:04 AnsonCode

@caoyanbin1993 这个只有自己进行改造。并发安全那边需要一个分布式锁(redis实现)。其实都还好。这个包很久没有更新了。有不少bug

XuHaoIgeneral avatar Apr 18 '19 03:04 XuHaoIgeneral

为啥用分布式锁呢,单机模式用普通的锁可以不?希望大神看看我这个代码,能不能帮忙完善下。

AnsonCode avatar Apr 18 '19 03:04 AnsonCode

我是个菜逼2333. 应届失业。

应为现在很多都是跑在docker环境下,一般都是3个服务,然后相互之间会有争抢更新的。若不做分布式锁,在access_token 更新的时候可能会有冲突,3个docker可能存在同时发起请求,若用锁来进行锁定,每次更新就只会有一个会去做全局的更新。 原来实习出过类似的事故,a容器更新了access_token b同时也更新,然后被覆盖,更新窗口内连接a容器ip的用户会操作失败。

大佬nb。

------------------ 原始邮件 ------------------ 发件人: "caoyanbin1993"[email protected]; 发送时间: 2019年4月18日(星期四) 中午11:14 收件人: "chanxuehong/wechat"[email protected]; 抄送: "徐浩"[email protected]; "Comment"[email protected]; 主题: Re: [chanxuehong/wechat] 微信access_token中控服务器 (#253)

为啥用分布式锁呢,单机模式用普通的锁可以不?希望大神看看我这个代码,能不能帮忙完善下。

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

XuHaoIgeneral avatar Apr 18 '19 03:04 XuHaoIgeneral

为什么是三个服务呢,做的是分布式部署吧?用缓存还是redis的关键是,锁的实现方式吧?access_token可以用一个服务进行管理,其他应用都请求他,应该是可以的。关键是写入时,要加锁。

AnsonCode avatar Apr 18 '19 03:04 AnsonCode

access_token 确实是可以自己单独做一个进行管理。 but:这个包的貌似没有解决方案。 有兴趣可以一起试一试,因为越来越多的环境有k8s了。

------------------ 原始邮件 ------------------ 发件人: "caoyanbin1993"[email protected]; 发送时间: 2019年4月18日(星期四) 中午11:26 收件人: "chanxuehong/wechat"[email protected]; 抄送: "徐浩"[email protected]; "Comment"[email protected]; 主题: Re: [chanxuehong/wechat] 微信access_token中控服务器 (#253)

为什么是三个服务呢,做的是分布式部署吧?用缓存还是redis的关键是,锁的实现方式吧?access_token可以用一个服务进行管理,其他应用都请求他,应该是可以的。关键是写入时,要加锁。

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

XuHaoIgeneral avatar Apr 18 '19 03:04 XuHaoIgeneral