微信公众号使用cookie存储access_token导致的一直重新获取超次数问题
最近做了一个项目,包含微信公众号的推送告警功能,在看着微信开发文档的基础上写完了,大概的就是获取access_token、并与openId、template_id和告警内容结合来实现对用户的推送提醒。但是access_token有2小时的过期时限,且有获取次数的限制。所以在获取完之后,我便将其放入到cookies之中,并定义2小时的过期期限,判断是重新获取还是使用原有的access_token。
在本地tomcat中测试毫无问题,以为已经解决了这个功能点。想想还是太天真。有一天突然发现怎么前一天的告警在下午2点多就不在告警,进入公众号里面却有数据。满怀忐忑的打开微信公众平台,果然2000次的次数已经爆表!
打开后台的调试日志,发现每次都是重新获取了access_token,而没有使用cookie中的access_token。
根据前几次的cookies读写错误问题,让我彻底的放弃cookies操作,使用文件进行对access_token的存储。
以下为公众号推送与access_token文件存取的代码(获取accesstoken方法不是重点,这里便不再累述了):
@RestController
public class PushController extends BaseController{
private static Logger log = LoggerFactory.getLogger(PushController.class);
@RequestMapping("/alarm/push")
public String alarm_push(HttpServletRequest request,HttpServletResponse response,@RequestBody WechatAlarmPush wechatAlarmPush) throws Exception {
String result = null;
String stationName = wechatAlarmPush.getStationName();
String alarmDesc = wechatAlarmPush.getAlarmDesc();
String alarmCode = wechatAlarmPush.getAlarmCode();
String alarmDateTime = wechatAlarmPush.getAlarmDateTime();
String alarmEndDateTime = "";
if(!StringUtils.isEmpty(wechatAlarmPush.getAlarmEndDateTime())) {
alarmEndDateTime = wechatAlarmPush.getAlarmEndDateTime();
}
String openId = wechatAlarmPush.getOpenId();
Integer stationId = wechatAlarmPush.getStationId();
//Integer systemType = wechatAlarmPush.getSystemType();
Integer systemType = 1;
ArrayList<Devices> devices = wechatAlarmPush.getDevices();
String deviceNames = "";
Integer deviceId = 0;
for (int i = 0; i < devices.size(); i++) {
String deviceName = devices.get(i).getName();
deviceId = devices.get(i).getId();
if(i != devices.size()-1) {
deviceNames = deviceNames+deviceName+"、";
}else {
deviceNames = deviceNames+deviceName;
}
}
Appkey appkey = new Appkey();
String appId = appkey.getWechatappid();
String appsecret = appkey.getWechatappsecret();
String alarm_template_id = appkey.getalarm_template_id();
String access_token = "no_token";
String server_url = appkey.getserver_url();
String url = "";
String unionid ="";
url = "跳转的链接";
alarmDesc = alarmDesc+"("+alarmCode+")";
Map<String,Cookie> cookieMap = ReadCookieMap(request);
log.debug("push access_token cookieMap:" + cookieMap);
access_token = getOldaccesstoken(appId,appsecret,1);
result = push_alarm(response,openId,alarm_template_id,url,alarmDesc,alarmDateTime,alarmEndDateTime,deviceNames,stationName,access_token);
return result;
}
//获得已经有的access_token
public String getOldaccesstoken(String appId,String appsecret,Integer type) {
final long MAX_TIME = 7200 * 1000;
Gson gson=new Gson();
String Accesstoken=null;
//1.创建一个路径对象,用来保存access_token
File file = new File("temp_access_token.temp");
//2.如果文件不存在
try {
if(!file.exists()) {
//2.1创建文件
file.createNewFile();
}
//2.2如果文件大小等于0,说明第一次使用,存入Access_token,type为0是重置
if (file.length() == 0||type == 0) {
String assccesstoken = WeChatAPIProxy.getAccessToken(appId,appsecret);
System.out.println("重新获取token是"+assccesstoken);
JSONObject data = JSONObject.fromObject(assccesstoken);
Integer errcode = 0;
errcode = data.optInt("errcode");
if(errcode == 0) {
Accesstoken = data.optString("access_token");
FileOutputStream fos = new FileOutputStream(file, false);
//2.2.3实例化一个AccessToken,将access_token和当前时间存进去
PushAccessToken accessToken=new PushAccessToken();
accessToken.setAccessToken(Accesstoken);
accessToken.setExpiresIn(System.currentTimeMillis() + "");
//2.2.4转换成json格式的字符串
String json = gson.toJson(accessToken);
//2.2.5将字符串写入到file文件中,getBytes()将字符串转换成字节数组byte[]
fos.write((json).getBytes());
fos.close();
//2.2.6 返回token值
}
return Accesstoken;
}else {
//2.3如果文件大小不等于0
//2.3.1实例化FileInputStream对象
FileInputStream fis = new FileInputStream(file);
//2.3.2定义一个数组
byte[] b = new byte[2048];
//2.3.3InputStreamReader的int read(char []cbuf);//将读取到的字符存到数组中。返回读取的字符数。
int len = fis.read(b);
//2.3.4读取到的文件内容
String mJsonAccess_token = new String(b, 0, len);
//2.3.5将json字符串转换成AccessToken类的对象
PushAccessToken accessToken = gson.fromJson(mJsonAccess_token,PushAccessToken.class);
//2.3.6如果expires_in不等于零,进行比较
if (accessToken.getExpiresIn() != null) {
//获取存入时的时间毫秒数
long saveTime = Long.parseLong(accessToken.getExpiresIn());
//获取现在时间的毫秒数
long nowTime = System.currentTimeMillis();
//做差值
long remianTime = nowTime - saveTime;
//如果差值小于MAX_TIME,token值
if (remianTime < MAX_TIME) {
/*AccessToken at = gson.fromJson(mJsonAccess_token,AccessToken.class);*/
Accesstoken = accessToken.getAccessToken();
fis.close();
//返回token
return Accesstoken;
} else {
//如果大于MAX_TIME,重新获取token
String assccesstoken = WeChatAPIProxy.getAccessToken(appId,appsecret);
JSONObject data = JSONObject.fromObject(assccesstoken);
Integer errcode = 0;
errcode = data.optInt("errcode");
if(errcode == 0) {
Accesstoken = data.optString("access_token");
FileOutputStream fos = new FileOutputStream(file, false);
//2.2.3实例化一个AccessToken,将access_token和当前时间存进去
PushAccessToken accessToken1=new PushAccessToken();
accessToken1.setAccessToken(Accesstoken);
accessToken1.setExpiresIn(System.currentTimeMillis() + "");
//2.2.4转换成json格式的字符串
String json = gson.toJson(accessToken1);
//2.2.5将字符串写入到file文件中,getBytes()将字符串转换成字节数组byte[]
fos.write((json).getBytes());
fos.close();
//2.2.6 返回token值
}
return Accesstoken;
}
}
fis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public String push_alarm(HttpServletResponse response,String openId,String alarm_template_id,String url,String alarmDesc,String alarmDateTime,String alarmEndDateTime,String deviceNames,String stationName,String access_token) {
String result = null;
JSONObject json = new JSONObject();
json.put("touser", openId);
json.put("template_id", alarm_template_id);
json.put("url", url);
JSONObject dataJson = new JSONObject();
PushTemplateData first = new PushTemplateData();
if(alarmEndDateTime.equals("")) {
first.setValue("您好,发生告警");
}else {
first.setValue("您好,告警已结束");
}
first.setColor("#1e90ff");
dataJson.put("first",first);
PushTemplateData keyword1 = new PushTemplateData();
keyword1.setValue(alarmDesc);
keyword1.setColor("#FF0000");
dataJson.put("keyword1",keyword1);
PushTemplateData keyword2 = new PushTemplateData();
keyword2.setValue(alarmDateTime);
keyword2.setColor("#1e90ff");
dataJson.put("keyword2",keyword2);
PushTemplateData keyword3 = new PushTemplateData();
keyword3.setValue(deviceNames);
keyword3.setColor("#1e90ff");
dataJson.put("keyword3",keyword3);
PushTemplateData keyword4 = new PushTemplateData();
keyword4.setValue(stationName);
keyword4.setColor("#1e90ff");
dataJson.put("keyword4",keyword4);
PushTemplateData remark = new PushTemplateData();
if(alarmEndDateTime.equals("")) {
remark.setValue("正在告警中,请及时处理。");
remark.setColor("#FF0000");
}else {
remark.setValue("告警于"+alarmEndDateTime+"结束");
remark.setColor("#1e90ff");
}
dataJson.put("remark",remark);
net.sf.json.JSONObject json_test = net.sf.json.JSONObject.fromObject(dataJson);
json.put("data", dataJson);
try {
result = WeChatAPIProxy.sendTemplateMsg(access_token,json.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//应对不知名情况报错
JSONObject resultJSON = JSONObject.fromObject(result);
if(resultJSON.optString("errcode").equals("40001")) {
Appkey appkey = new Appkey();
String appId = appkey.getWechatappid();
String appsecret = appkey.getWechatappsecret();
access_token = getOldaccesstoken(appId,appsecret,0);
result = push_alarm(response,openId,alarm_template_id,url,alarmDesc,alarmDateTime,alarmEndDateTime,deviceNames,stationName,access_token);
}
return result;
}
/**
* 将cookie封装到Map里面
* @param request
* @return
*/
private static Map<String,Cookie> ReadCookieMap(HttpServletRequest request){
Map<String,Cookie> cookieMap =new HashMap<String,Cookie>();
Cookie[] cookies = request.getCookies();
if(null!=cookies){
for(Cookie cookie : cookies){
cookieMap.put(cookie.getName(), cookie);
}
}
return cookieMap;
}
}
相对应的PushAccessToken类:
/**
* 用户授权token
*/
public class PushAccessToken {
private String accessToken;
private String expiresIn;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(String expiresIn) {
this.expiresIn = expiresIn;
}
}