wechat
wechat copied to clipboard
微信access_token中控服务器
假如我的应用需要对接多个微信公众号,且需要在不重启服务器的情况下,新增或更改公众号的appid等信息,那么公众号的【access_token中控服务器】的tokenUpdateDaemon进程如何销毁呢?
可以考虑自己重写一部分信息。在切换的时候,更改appid。
我重新实现了中控服务器接口,用缓存存储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
}`
@caoyanbin1993 这个只有自己进行改造。并发安全那边需要一个分布式锁(redis实现)。其实都还好。这个包很久没有更新了。有不少bug
为啥用分布式锁呢,单机模式用普通的锁可以不?希望大神看看我这个代码,能不能帮忙完善下。
我是个菜逼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.
为什么是三个服务呢,做的是分布式部署吧?用缓存还是redis的关键是,锁的实现方式吧?access_token可以用一个服务进行管理,其他应用都请求他,应该是可以的。关键是写入时,要加锁。
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.