微信公众平台开发时,微信推送消息的机制是推送过来后如果5秒内收不到响应则认为没有推送成功,会再次推送,如果5秒内仍没有收到响应继续推送,总共推送三次。
微信文档原文:
普通消息
1、关于重试的消息排重,推荐使用msgid排重。
2、微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。
事件推送:
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。
假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。
我的解决方案:
1.创建判断重复消息的DuplicateRemovalMessage类;
2.把微信推送的消息解析赋值给DuplicateRemovalMessage对象实例;
3.用静态变量list当缓存,判断DuplicateRemovalMessage实例是否存在于缓存list中,如果存在则为重复消息,如果不存在则不是重复消息并把消息放到缓存list中。
此方案弊端:
1.缓存list会无限增大,所以用setMessageToCache方法限制了list最大容量为1000;
2.解决了list最大容量依然还有弊端,就是两条重复的消息之间如果有超过999个DuplicateRemovalMessage对象依然会判断不准,只能增大list容量来缓解,由于这种情况比较极端,目前远没有那么大业务量,所以暂时这么用着了。
大家有什么好的解决方案一起交流,欢迎拍砖。
下面是具体实现代码:
注意:DuplicateRemovalMessage别忘记复写hashcode、equals方法
private static final int MESSAGE_CACHE_SIZE = 1000;
private static List<DuplicateRemovalMessage> MESSAGE_CACHE = new ArrayList<DuplicateRemovalMessage>(MESSAGE_CACHE_SIZE);
/**
* @Description: 判断微信请求是否重复
* @return boolean 如果重复返回true
*/
public static boolean isDuplicate(Map<String, String> request) {
String fromUserName = request.get("FromUserName");
String createTime = request.get("CreateTime");
String msgId = request.get("MsgId");
DuplicateRemovalMessage duplicateRemovalMessage = new DuplicateRemovalMessage();
if (msgId != null) {
duplicateRemovalMessage.setMsgId(msgId);
} else {
duplicateRemovalMessage.setCreateTime(createTime);
duplicateRemovalMessage.setFromUserName(fromUserName);
}
if (MESSAGE_CACHE.contains(duplicateRemovalMessage)) {
// 缓存中存在,直接pass
return true;
} else {
setMessageToCache(duplicateRemovalMessage);
return false;
}
}
private static void setMessageToCache(DuplicateRemovalMessage duplicateRemovalMessage) {
if (MESSAGE_CACHE.size() >= MESSAGE_CACHE_SIZE) {
MESSAGE_CACHE.remove(0);
}
MESSAGE_CACHE.add(duplicateRemovalMessage);
}
DuplicateRemovalMessage对象:
public class DuplicateRemovalMessage {
private String MsgId;
private String FromUserName;
private String CreateTime;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((CreateTime == null) ? 0 : CreateTime.hashCode());
result = prime * result + ((FromUserName == null) ? 0 : FromUserName.hashCode());
result = prime * result + ((MsgId == null) ? 0 : MsgId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DuplicateRemovalMessage other = (DuplicateRemovalMessage) obj;
if (CreateTime == null) {
if (other.CreateTime != null)
return false;
} else if (!CreateTime.equals(other.CreateTime))
return false;
if (FromUserName == null) {
if (other.FromUserName != null)
return false;
} else if (!FromUserName.equals(other.FromUserName))
return false;
if (MsgId == null) {
if (other.MsgId != null)
return false;
} else if (!MsgId.equals(other.MsgId))
return false;
return true;
}
public String getMsgId() {
return MsgId;
}
public void setMsgId(String msgId) {
MsgId = msgId;
}
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public String getCreateTime() {
return CreateTime;
}
public void setCreateTime(String createTime) {
CreateTime = createTime;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("DuplicateRemovalMessage [MsgId=");
builder.append(MsgId);
builder.append(", FromUserName=");
builder.append(FromUserName);
builder.append(", CreateTime=");
builder.append(CreateTime);
builder.append("]");
return builder.toString();
}
}