一、access_token简介
access_token是公众号接口调用的凭据,公众号调用各接口时均需使用access_token。
例如:
1)创建自定义菜单接口:
https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
2)获取素材列表接口:
https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN
3)获取用户基本信息接口:
https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
等等,这些接口的请求地址均需要一个ACCESS_TOKEN参数,该参数就需要调用获取access_token接口来获取
注意:
1)access_token有时效性,当前有效时间为7200秒,需要的存储空间为512个字符空间,需要注意的是,微信后期有可能会改这个access_token的过期时间
2)如果在布署中有多台业务逻辑服务器均在自己的程序中获取access_token,这将造成多次刷新access_token的情况,建议布署中通过一台中控服务器来统一获取,或者将access_token存入缓存中统一读取
二、access_token获取方式
1、接口请求地址:
http请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
2、请求参数说明:
参数 | 是否必须 | 说明 |
grant_type | 是 | 获取access_token固定为client_credential |
appid | 是 | 第三方用户唯一任证 |
secret | 是 | 第三方用户唯一任证密钥 |
注:appid和secret对应的是公众平台后台中,【开发】选项中的【基本配置】中AppID和AppSecret
3、返回说明:
1)成功
{"access_token":"ACCESS_TOKEN","expires_in":7200}
2)失败
{"errcode":40013,"errmsg":"invalid appid"}
三、access_token获取代码实现
下面是access_token获取的java实现,注该代码中json解析使用到了阿里巴巴的fastjson
package cn.kolbe.wechat.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
/**
* 获取微信accessToken
* @author admin
*
*/
public class AccessTokenUtil {
private static final String APP_ID = "xxxxxxx";
private static final String APP_SECRET = "xxxxxx";
// 当前程序使用的accessToken
private static String accessToken = "";
// 微信获取accessToken的接口地址
private static final String GET_ACCESS_TOKEN_API = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APP_ID + "&secret=" + APP_SECRET;
// accessToken的过期时效
private static final int EXPIRED_SECONDS = 7200;
// 当前最后更新accessToken的日期
private static Date latestDate = new Date();
/**
* 获取accessToken
* @return
*/
public static String getToken() {
Date now = new Date();
if((now.getTime() - latestDate.getTime()) < EXPIRED_SECONDS*1000 && !accessToken.equals("")) {
System.out.println("已经存在accessToken," + accessToken);
return accessToken;
} else {
// 防止并发环境下,重复更新accessToken
synchronized(AccessTokenUtil.class) {
if((now.getTime() - latestDate.getTime()) < EXPIRED_SECONDS*1000 && !accessToken.equals("")) {
System.out.println("accessToken已经被更新过," + accessToken);
return accessToken;
}
System.out.println("accessToken过期,重新生成," + accessToken);
latestDate = new Date();
JSONObject json = JSON.parseObject(sendGet(GET_ACCESS_TOKEN_API));
accessToken = json.getString("access_token");
return accessToken;
}
}
}
/**
* 简易发送Http的Get请求
* @param urlStr
* @return
*/
private static String sendGet(String urlStr) {
URL url = null;
URLConnection conn = null;
BufferedReader reader = null;
try {
url = new URL(urlStr);
conn = url.openConnection();
conn.connect();
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
StringBuilder result = new StringBuilder();
String s = new String();
while((s = reader.readLine()) != null) {
result.append(s);
}
return result.toString();
} catch(Exception e) {
e.printStackTrace();
return null;
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 测试并发环境下,获取accessToken
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
for(int i = 0; i < 100; i++) {
if(i % 10 == 0) {
Thread.sleep(1000);
}
executor.submit(new AccessTokenUtil.AccessTokenThread());
}
}
/**
* 模拟并发环境下,获取accessToken
* @author admin
*
*/
public static class AccessTokenThread implements Runnable {
@Override
public void run() {
AccessTokenUtil.getToken();
}
}
}
注:
1)该代码中并没有考虑错误情况下的处理方式(建议提供一个强制刷新accessToken的方法)
2)刷新accessToken时,需要注意考虑并发情况下,同时多个线程发现accessToken过期,重复去刷新accessToken的情况,代码中已经通过加锁来防止这种情况的发生
转载于:https://my.oschina.net/kolbe/blog/663173