Comet:Jquery+asp.net实现http长连接(LongPoll)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="JqueryAjaxLongPoll.aspx.cs" Inherits="JqueryAjaxLongPoll" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>无标题页</title> <script type="text/javascript" src="script/jquery-1.2.6.js"></script> <script type="text/javascript"> $(document).ready(function(){ $("#Button1").bind("click",{btn:$("#Button1")},function(evdata){ $.ajax({ type:"POST", url:"JqueryAjaxLongPoll.aspx", dataType:"json", timeout:10000, data:{ajax:"1",time:"10000"}, success:function(data,textStatus){ //alert("ok!"); evdata.data.btn.click(); }, complete:function(XMLHttpRequest,textStatus){ if(XMLHttpRequest.readyState=="4"){ alert(XMLHttpRequest.responseText); } }, error: function(XMLHttpRequest,textStatus,errorThrown){ //$("#ajaxMessage").text($(this).text()+" out!") alert("error:"+textStatus); if(textStatus=="timeout") evdata.data.btn.click(); } }); }); /*$("#ajaxMessage").ajaxStart(function(){ $(this).text("准备建立请求.readyState0:"); }); $("#ajaxMessage").ajaxSend(function(evt, request, settings){ $(this).text("开始请求,准备发送数据.readyState1:"+request.readyState); }); $("#ajaxMessage").ajaxComplete(function(event,request, settings){ if(request.status==200) $(this).text("请求完成.readyState4:"+request.readyState); }); $("#ajaxMessage").ajaxStop(function(){ $(this).text("请求结束."); });*/ }); </script> </head> <body> <form id="form1" runat="server"> <div> <input id="Button1" type="button" value="AjaxLongPoll" /> <label id="ajaxMessage"></label> </div> </form> </body> </html>
using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Threading; public partial class JqueryAjaxLongPoll : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (Request.Form["ajax"] == "1") { //Response.End(); int time = Convert.ToInt32(Request.Form["time"]); DateTime date1 = DateTime.Now.AddMilliseconds((double)time); bool ready = false; while (Response.IsClientConnected) { Thread.Sleep(3000); if (DateTime.Compare(date1, DateTime.Now) < 0) { Response.End(); break; } //ready = true; if (ready) { Response.Write("SetValue('" + DateTime.Now.ToString() + "')"); //Response.Flush(); Response.End(); break; } else { } } } else { if (!Page.IsPostBack) { } } } }
对代码的说明:利用jquery,很方便的就能实现ajax,上面设置了ajax的timeout时间,由于设置了timeout将会造成不能保持长连接,到了时间ajax自动会报“超时”的错误,也就是会调用error方法,此时textStatus=="timeout",timeout后重新进行ajax请求。服务器接受ajax请求的时候,会接收一个超时时间的值,超时的情况下服务器端的处理也立即停止。当客户端成功获取返回结果时,也会立即进行新的ajax请求,如此循环。
为什么要设置客户端的ajax超时值呢?因为服务器为了保持请求(阻塞请求),必须有一个无限循环,循环的结束条件就是获取到了返回结果,如果客户端关闭了(客户端浏览器的关闭不会发消息给服务器),服务器无法知道客户端已经关了,这个请求没必要处理下去了。最终会造成资源过度浪费,只要用一个折中的办法,限制超时时间。
可以不必设置客户端ajax的超时时间,但进行请求的时候传递一个超时值给服务器,服务器在处理的时候,如果超时时间到了的话,还没有客户端需要的结果,这时传递一个超时信息给客户端,客户端接收到了此信息,根据情况重新进行ajax请求。XMLHttpRequest没有超时的参数,Jquery用window.setTimeout自己封装的(到了定时时间运行超时处理方法,和XMLHttpRequest结束方法)。可以根据这个思路来改变一下,IBM上介绍的LONG POLL好像也是这样的。
$(document).ready(function(){ $("#Button1").bind("click",{btn:$("#Button1")},function(evdata){ $.ajax({ type:"POST", url:"JqueryAjaxLongPoll.aspx", dataType:"json", data:{ajax:"1",time:"6000000"}, success:function(data,textStatus){ //成功 if(data.success=="1"){ //客户端处理 //... ///重新请求 evdata.data.btn.click(); } //超时 if(data.success=="0"){ evdata.data.btn.click(); } }, complete:function(XMLHttpRequest,textStatus){ if(XMLHttpRequest.readyState=="4"){ alert(XMLHttpRequest.responseText); } }, error: function(XMLHttpRequest,textStatus,errorThrown){ //$("#ajaxMessage").text($(this).text()+" out!") // alert("error:"+textStatus); // if(textStatus=="timeout") evdata.data.btn.click(); } }); });
后台代码变更后:
if (Request.Form["ajax"] == "1") { int time = Convert.ToInt32(Request.Form["time"]); DateTime date1 = DateTime.Now.AddMilliseconds((double)time); bool ready = false; while (Response.IsClientConnected) { Thread.Sleep(3000); if (DateTime.Compare(date1, DateTime.Now) < 0) { Response.Write("{success:'0'}"); Response.End(); break; } //此处进行请求处理,有结果了置ready = true //ready = true; if (ready) { Response.Write("{success:'1'}"); Response.End(); break; } } } else { if (!Page.IsPostBack) { } }
上面的方法应该就可以满足要求了,具体的超时时间可以根据情况来设置。这也是我根据IBM上介绍的“server push”思路,来实现了其中的一种,也不知道有没有问题,还请大家多多赐教。