1、建议公众号开发者使用中控服务器统一获取和刷新Access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;
2、目前Access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器可对外继续输出的老access_token,此时公众平台后台会保证在5分钟内,新老access_token都可用,这保证了第三方业务的平滑过渡;
3、Access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。
公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。
2)jsapi_ticket
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html
2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
三:access_token中控器
access_token每天有使用次数限制,所以客户服务器不能每次是都去请求一个新的access_token,每次请求之后,access_token都有一个过期时间。因此微信平台建议你使用一个中控服务器来定时刷新token,取得之后存起来不用再去请求token,因为access_token请求有次数限制。 这样处理只有有两个好处:
- 保证access_token每日都不会超出访问限制,保证服务的正常。
- 提高服务的性能,不用每次发送业务请求之前都先发送一次access_token获取请求。
1)注册监听器
public class TokenListener implements ServletContextListener{
private static Logger log = Logger.getLogger(TokenListener.class);
private Timer timer = null;
@Override
public void contextInitialized(ServletContextEvent arg0) {
log.info("accessToken监听器启动..........");
timer = new Timer(true);//Timer是调度控制器,TimerTask是可调度的任务
//注册定时任务
registeAccessTokenTimer();
//注册jsapi_ticket定时器
registeJsApiTicketTimer();
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
timer.cancel();
}
/**
* 注册accessToken定时器
*/
private void registeAccessTokenTimer(){
AccessTokenTimer accessTokenTimer = new AccessTokenTimer();
timer.schedule(accessTokenTimer, AccessTokenTimer.DELAY,AccessTokenTimer.PERIOD);
log.info("accessToken定时器注册成功,执行间隔为" + AccessTokenTimer.PERIOD);
}
/**
* 注册jsapi_ticket定时器
*/
private void registeJsApiTicketTimer(){
JsApiTicketTimer jsApiTicketTimer = new JsApiTicketTimer();
timer.schedule(jsApiTicketTimer, JsApiTicketTimer.DELAY,JsApiTicketTimer.PERIOD);
log.info("jsapi_ticket定时器注册成功,执行间隔为" + JsApiTicketTimer.PERIOD);
}
}
2)定时器,7000s刷新一下
public class AccessTokenTimer extends TimerTask{
private static Logger logger = Logger.getLogger(AccessTokenTimer.class);
//accessToken有效期7200秒,提前200秒请求新的token
public static final long PERIOD = 7000 * 1000;
public static final long DELAY = 0; //此任务的延迟时间为0,即立即执行
@Override
public void run() {
logger.info("accessToken 定时任务启动,获取新的accessToken");
//得到新的access token
AccessToken accessToken = new AccessToken();
//获取成功之后持久化accessToken
if(accessToken.request()){
AccessTokenServer accessTokenServer = new AccessTokenServer();
CustomerServer customerServer = (CustomerServer)accessTokenServer.customerServer();
customerServer.save(accessToken);
}
}
}
3)保存到数据库
public class CustomerAccessTokenServer extends CustomerServer {
private BaseDaoImpl baseDaoImpl = SpringContextHolder.getBean("baseDaoImpl");;
protected String query() {
String accessToken = null;
// 执行数据库操作
String sql = "select cfgValue from x_cfg where cfgKey = 'access_token'";
List
4)启动后
2017-12-09 23:29:52,796 INFO [com.xyx.test.TokenListener] -
2017-12-09 23:29:52,796 INFO [com.xyx.test.TokenListener] -
2017-12-09 23:29:52,796 INFO [com.xyx.test.timer.AccessTokenTimer] -
2017-12-09 23:29:52,796 INFO [com.xyx.test.AccessToken] - <创建获取access_token url>
2017-12-09 23:29:52,796 INFO [com.xyx.test.TokenListener] -
2017-12-09 23:29:53,688 INFO [com.xyx.test.token.Token] -
2017-12-09 23:29:53,688 INFO [com.xyx.dao.impl.BaseDaoImpl] -
2017-12-09 23:29:53,688 INFO [com.xyx.dao.impl.BaseDaoImpl] -
2017-12-09 23:29:53,736 INFO [com.xyx.test.timer.JsApiTicketTimer] -
2017-12-09 23:29:53,736 INFO [com.xyx.dao.impl.BaseDaoImpl] -