一、问题解决的背景和意义
在很多购物网站中,特别是在一些产品购买浏览页面中,我们需要抓取用户浏览的一些行为。比如说某个页面的用户浏览时间,分享的次数,以便能给销售团队提供用户行为的信息,方便以后的销售策略的调整。在普通的网页中,其实是个很容易实现的需求——监听popstate,visualbilitychange等浏览器全局事件的回调即可。但是在微信内部访问的网页中,特别是微信iOS版本中,问题就变得非常复杂了,这些全局事件的表现变得捉摸不定,在2017年3月微信iOS客户端换为wkwebview内核以后,单纯靠前端的逻辑,基本上没有办法获取到前端的用户浏览网页时间了,于是我们就准备用websocket来解决这个问题。
二、websocket的实现方法的简述和遇到的问题
在实现尝试实现的过程中,观察和遇到了这样几个问题。第一个问题是基于jsr-356标准的websocket实现与spring整合的问题,如果不解决这个问题就会导致在websocket的接口里无法自动组装(@Autowired)在spring context里的Bean。第二个问题是当用户离开当前页面时,普通浏览器会立即断开当前页发起的websocket链接,而在微信中的网页不会。在微信中websocket长连接会一直保持链接,直至用户锁屏,或再次发起另一个websocket握手请求时,上一个连接才会断开。这样的现象导致我们不得不在服务端实现心跳检测来侦测用户是否真的离开了目标页面。
OK, SHOW ME THE CODE!
三、心跳检测在tomcat下基于JSR-356实现的大致步骤
tips: demo地址websocket-heartbreak.git
(1)websocket服务端的实现
/**
*
* websocket heart break endpoint
* client side viewing-time count
*
* @author zhiheng
*
*/
@ServerEndpoint(value = "/websocket/count")
public class HeartBreakEndpoint {
private Timer timer;
private volatile boolean isPong;
private long startTime;
@OnOpen
public void start(final Session localSession) {
this.startTime = System.currentTimeMillis();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
if(isPong) {
System.out.println("Timer - Say hi");
localSession.getBasicRemote().sendText("hi");
isPong = false;
} else {
System.out.println("INFO - Check the time.");
try {
localSession.close();
} catch (IOException e) {
e.printStackTrace();
}
this.cancel();
}
} catch (IOException e) {
e.printStackTrace();
this.cancel();
}
}
}, 2000, 2000);
}
@OnClose
public void onClose() {
long currTime