最近给客户做了个微信公众号,其中在菜单上配置的查询功能需要访问客户系统接口获取数据;
微信端的http请求在一定时间内(微信开发文档中写的是5s,实际开发查看报文是7s)无法得到返回的话会重发此请求。
微信的请求中会带有一个code参数用于再次请求微信服务器获取微信用户信息,重发请求发送的也是相同的code;
而这个code是一次性的,action在接到重发请求时无法通过相同的code再次获取微信用户信息。
项目会先通过code获取微信用户的OpenID,再查询客户系统接口。
但客户的系统接口查询比较慢,大约30秒左右,所以第一次的查询通过code获得了微信用户的openID并等待客户系统返回查询结果时候,微信会用相同的code发起重发请求;
而重发请求的code由于已经被使用过,是无法获得微信用户的OpenID的,所以系统会先于第一次查询返回给微信client端一个查询失败的结果页,导致查询功能不能使用。
由此,想出了以下的解决方案:
1.联系客户系统提升接口速度
——联系过客户进行优化,速度没有提升
2.联系微信客服尝试修改重发时间限制
——微信客服没有回应
3.保存code,并过滤掉相同code的重发请求
——用filter和servlet写demo测试没有能成功实现拦截请求,总是会返回一个空白页面
4.增加loading页面相应微信端请求,再异步执行查询action
——这里的实现上有很多种:
4.1在原有页面中增加loading蒙版,并使用AJAX异步请求Action查询
——原来的页面使用JSTL获取数据,改由使用AJAX传递JSON与Action进行数据交互的话,页面的获取方式和Action类的返回方式都需要重写
4.2新建loading页面
实现后发现这种办法比我想象的简单,单独的一个页面实现loading的js效果,并且在页面中加入如下的逻辑先获取微信用户的OpenID:
WeiXinClient weixin = new WeiXinClient ();
String OpenID = weixin.getOpenId(request);
并在页面中加入如下JS代码即可实现效果:
$(document).ready(function(){
modal_loading();
document.location.href="/action/getInfo?OpenID=<%=OpenID%>";
});
modal_loading();是页面loading的JS方法,这部分JS源码的实现方式我没看懂,网上应该有很多类似JS功能代码;
Action类中的逻辑执行完成后会直接跳转到结果展示页,这样原来的Action和展示页面都不用改。
附:WeiXinClient中的功能代码,感谢实现这部分功能的我的同事:-P:
public static String getOpenId(HttpServletRequest req){
String code = req.getParameter("code");//获取code
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+"公众号的AppId"+"&secret="+"公众号AppSecret"+"&code="+code+"&grant_type=authorization_code";
JSONObject json = CommonUtil.httpsRequest(url, "GET", null);
String openId = (String)json.get("openid");
return openId;
}