关闭

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

标签: 三次微信异步排重AsyncContent
5140人阅读 评论(0) 收藏 举报
分类:

问题来源: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中

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

总结:

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

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

2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9256次
    • 积分:183
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类