微信服务器发送三次重复的排重问题

来源:互联网 发布:南风知我意七微txt下载 编辑:程序博客网 时间:2024/04/30 06:08

问题来源:http://www.zhihu.com/question/22685171

微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次

由于微信官方的服务器在处理消息时候的特殊方式,导致了这种问题的发生

微信的本意是为了在丢包稍微严重的情况下服务依旧能正常运行,但是这样给开发者确提升了难度

一般是每隔5s发送一次请求的,但是如果我们的处理是耗时操作怎么办呢,我们在第10s才能结束操作,这怎么办>>>>>>>>>>>>>>>>>>

--------仅用于企业号和服务号

1.就和回答中的Aloong兄弟那样说的,我们可以先给微信服务器反馈一个空白或者不空白的数据(XML或者非XML都行),然后调用微信的高级接口,给用户发送数据即可(理由:我们反馈了一个任意数据,微信服务器认为他的工作完成了,就不会再重复发送数据了,此时我们再调用高级接口发送数据也就不会有干扰了-即使是用户短时间内多次发送请求)

流程:

a.得到数据response.getWriter();

b.得到数据request下的所有数据--->写入一个HashMap中

c.使用response的writer返回一个空白,并且关闭writer,注意如果不关闭的话,那么这个空白消息是不会被传给微信服务器的

d.使用之前的HashMap的值做我们的超时处理

--------通用方法

2.和李一峰兄弟说的那样,建立一个简单的list缓冲-相当于消息队列,来了一个消息之后就和list比对(有msgid的消息使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime[重复发送相同消息这个值是一样的] 排重。),遍历list发现如果在list中存在那么就不加入list,直接return,否则的话加入list,然后继续执行操作,执行完成后反馈即可---必须使用AsyncContext这种异步操作

流程:

a.新建一个静态全局ArrayList<XXX>,添加一个类XXX{msgid, FromUserName, CreateTime}

b.遍历list如果在list中,那么直接return || 如果不在list中,list.add就行了(return之后由于Async的存在连接不会断开,所以request和response不会释放,也就不会断开本次回话,如果不使用Async的话,微信的结束自己的任务,不会重复发送,问题是我们也发不出数据回去了)

c.耗时操作,并反馈XML数据回去

模拟:只在第三次的时候返回数据,其他时候挂起

Servlet中

[html] view plain copy
  1. int coutn = 1;  
  2. @Override  
  3.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  4.             throws ServletException, IOException {  
  5.         final AsyncContext asyncContext = request.startAsync(request, response);  
  6.         asyncContext.setTimeout(5000);  
  7. //      asyncContext.addListener(new AsyncListener()); 这里需要自己添加  
  8.         asyncContext.start(new Deal_Thread(asyncContext)); //新建一个自己的Thread类,类中执行应尽的操作  
  9.     }  
[html] view plain copy
  1.   
DealThread中
[html] view plain copy
  1. @Override  
  2.     public void run() {  
  3.         Date nDate = new Date(System.currentTimeMillis());  
  4.         PrintWriter pw = null;  
  5.         Map<String, String> userSendMap = null;  
  6.         try {  
  7.             pw = ((HttpServletResponse)this.context.getResponse()).getWriter();  
  8.             userSendMap = new dealXML().toMap((HttpServletRequest)this.context.getRequest());  
  9. //          if(is_exist(CoreServlet.list, (HashMap<String, String>)userSendMap))  
  10.             if(CoreServlet.coutn == 3) {  
  11.                 Message_Text message_Text = new EasyFunctions().genaText(userSendMap.get("FromUserName"), userSendMap.get("ToUserName"), "wocao");  
  12.                 pw.print(message_Text.toXMLString_And_enCode());  
  13.             }else{  
  14.                 CoreServlet.coutn++;  
  15.                 return;  
  16.             }  
  17.             pw.flush();  
  18.             pw.close();  
  19.         } catch (Exception e1) {  
  20.             e1.printStackTrace();  
  21.         }  
  22.     }  

总结:

第一种方法用着思维挺简单,操作也挺简单,但是要求必须是企业号或者是服务号,要求不高的话可以用这个方法,操作简单并且基本上不需要考虑多线程的问题

第二种方法比较好,适用于各种情况,不仅仅是在微信上的,但是需要考虑到请求的时间问题,所以比较复杂
0 0