lanrion / weixin_authorize

微信 Ruby 高级API weixin_authorize http://github.com/lanrion/weixin_authorize .
MIT License
322 stars 116 forks source link

获取access_token接口的每日实时调用量并没有变化的前提下,不定期出现了40001, access_token is invalid 错误 #94

Open yanchengv opened 8 years ago

yanchengv commented 8 years ago

调用$client.download_media_url(media_id) 或者$weixin.send_template_msg(): 不定期出现错误,但是微信的 每日实时调用量并没有变化,重复调用几次又正常了,一会又报错了。。。 {"code":40001,"en_msg":"invalid credential, access_token is invalid or not latest hint: [8KS0939ge11]","cn_msg":"获取access_token时AppSecret错误,或者access_token无效","result":{}}

lanrion commented 8 years ago

正在修复。

wikimo commented 8 years ago

@yanchengv

yanchengv commented 8 years ago

@wikimo @lanrion def send_template openid,template_id,data url = $weixin.authorize_url(‘http://www.jinhuo.com’) template_id = Settings.weixin.template1 response = $weixin.send_template_msg(openid, template_id, url, 'red', data) end

这种问题出现是由于部署由mina改为Capistrano引起的,后来改回mina就正常了。找了一下原因,猜测应该是worker_processes进程数量引起的。

一直泪奔过来了,现在恢复正常也没敢在动环境测试,等缓一缓我测试一下是否这个原因

lanrion commented 8 years ago

你是不是每台机器都new了一个 WeixinAuthorize::Client?这样子的话,会互相请求access_token的API,导致其他worker正在使用时失败。

请务必独立一个worker获取access_token,并让其他worker统一调用。

微信的官方wiki对此的解释:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN

1、为了保密appsecrect,第三方需要一个access_token获取和刷新的中控服务器。而其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则会造成access_token覆盖而影响业务;

weixin_authorize 使用自定义token的方法

https://github.com/lanrion/weixin_authorize/wiki/input-custom_access_token

即先在中控服务器使用weixin_authorize的 get_access_token接口获取,然后在其他业务服务器使用这些数据,参照wiki https://github.com/lanrion/weixin_authorize/wiki/input-custom_access_token

lanrion commented 8 years ago

同时建议使用Redis。

wikimo commented 8 years ago

这种基本就是重复调用引起的,建议源码也阅读下,以便于更好地使用gem @yanchengv

yanchengv commented 8 years ago
lanrion commented 8 years ago

workproess 如果是多个的话,可以看成是多个client获取access_token。

根据微信的建议,你需要独立获取access_token,然后供应给其他人使用。

lingceng commented 5 years ago

项目里用了 MonitorMixin 的 synchronize 来避免 access_token 的竞争。 但只能避免线程间的竞争,如果用 Puma 开启了多个进程,是容易出现重复刷新 access_token 的问题。

可以通过第三方存储的锁机制。例如,用Redis的写入锁

Redis.set('lock_key', 'refreshing', ex: 3, nx: true)

https://github.com/Eric-Guo/wechat 这个项目中用了随机数检查过期时间的方式,但这种方式会有不稳定的结果。

lanrion commented 5 years ago

@lingceng
获取access_token 最好是单独一台机器来维护. 添加分布式锁setnx 也是最好的方案.