comet

关于浏览器收不到tomcat comet数据的分析

         最近有一个基于web的通讯项目。经研究comet是很适合的技术,可以满足新项目的要求,对比了tomcatjettyglassfish决定还是使用常见的tomcat来进行测试和生产部署。tomcatcomet并不复杂,先用tomcat网站上的例子进行测试。

客户端接收代码:

function callback() //回调函数,对服务端的响应处理,监视response状态
{

 if(req.readystate==4) //请求状态为4表示成功

 

if(req.status==200) //http状态200表示OK 

{
                     
//所有状态成功,执行此函数,显示数据
}

         }
}

结果。。。。。没成功!!!

         IEFFfirefox)连接发送信息,接收数据的的IEFF并没有任何数据显示出来。于是用sinffer录了一下网络包,发现数据其实已经从tomcat推下来了,也就是浏览器已经接受到了数据。为什么浏览器没有显示呢?。。。

先研究一下tomcat推下来数据吧,tomcat使用chunked编码方式来进行报文体的传输。chunked编码是HTTP/1.1 RFC里定义的一种编码方式,因此所有的HTTP/1.1应用都应当支持此方式。
    chunked
编码的基本方法是将大块数据分解成多块小数据,每块都可以自指定长度,其具体格式如下(BNF文法):
    Chunked-Body   = *chunk            //0
至多个chunk
                     last-chunk         //
最后一个chunk 
                     trailer            //
尾部
                     CRLF               //
结束标记符

   chunk          = chunk-size [ chunk-extension ] CRLF   
                        chunk-data CRLF
   chunk-size     = 1*HEX
   last-chunk     = 1*("0") [ chunk-extension ] CRLF

   chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
   chunk-ext-name = token
   chunk-ext-val  = token | quoted-string
   chunk-data     = chunk-size(OCTET)
   trailer        = *(entity-header CRLF)     

也就是当用chunked的返回数据时,最后需要有一个长度为0的数据包表明数据结束。而恰恰是cometstream工作机制导致tomcat没有发送最后一个结束包给浏览器,浏览器认为数据没有接收完一直在等待,直到接收到最后一个包或者socket断开连接。

         知道了原因开始想解决办法。

首先想的是从服务器端解决。如果手动发一个chunked结束包不久可以了?后来发现发了结束包浏览器就会断开连接,要想服务器可以继续推数据只能重新建立连接,streamlong polling了。

服务器不行就从客户端想办法,既然IE认为数据没有接受全所以不会出发readystate==4这个状态,那我们用状态3可不可以呢?也就是改代码为:

function callback() //回调函数,对服务端的响应处理,监视response状态
{

 if(req.readystate==3) //请求状态为4表示成功

 

if(req.status==200) //http状态200表示OK 

{
                     
//所有状态成功,执行此函数,显示数据
}

         }
}

结果是firefox可以正常运行,IE还是不行提示“数据没有准备好“。看来FFIE存在差别,经查资料FF是基于Gecko引擎的,IE 则是基于Trident的。基于Gecko引擎的浏览器都可以很好的处理这种情况。这种方法不能使用,毕竟IE占据了绝大部分的浏览器市场。而且operasafari等其他浏览器对这个的支持也都不同。

         经过几天的研究又回到了很老的iframe解决办法上,通过iframe tomcatIE能够正常的工作了(FF还是有问题,数据回来到现实有延迟。由于我们的客户端都是IE所以这点也可以接受了)。最后就剩下一个小问题,IE上的加载图标不停老在那里转。。。。。

经过搜索使用天才google工程师的解决办法,成功解决大功告成!

以下是google的代码:

<script type="text/javascript">

var comet = {

  connection   : false,

  iframediv    : false,

 

  initialize: function() {

 

       var userAgent = navigator.userAgent.toLowerCase();

 

       //alert(userAgent)

    if (/msie/.test(userAgent) && !/opera/.test(userAgent)) {

 

      // For IE browsers

      comet.connection = new ActiveXObject("htmlfile");

      comet.connection.open();

      comet.connection.write("<html>");

      comet.connection.write("<script>document.domain = '"+document.domain+"';<//script> ");

      comet.connection.write("</html>");

      comet.connection.close();

      comet.iframediv = comet.connection.createElement("div");

      comet.connection.appendChild(comet.iframediv);

      comet.connection.parentWindow.comet = comet;

      comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='./Demo'></iframe>";

    }

 

    if( /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent) ) {

      // For Firefox browser

      comet.connection = document.createElement('iframe');

      comet.connection.setAttribute('id','comet_iframe');

      with (comet.connection.style) {

        left       = top   = "-100px";

        height     = width = "1px";

        visibility = "hidden";

        display    = 'none';

      }

      comet.iframediv = document.createElement('iframe');

      comet.iframediv.setAttribute('src', './Demo');

      comet.connection.appendChild(comet.iframediv);

      document.body.appendChild(comet.connection);

 

    }

    if (/webkit/.test(userAgent) || /opera/.test(userAgent)) {

 

           // for other browsers

      comet.connection = document.createElement('iframe');

      comet.connection.setAttribute('id',     'comet_iframe');

      comet.connection.setAttribute('src',    './Demo');

      with (comet.connection.style) {

        position   = "absolute";

        left       = top   = "-100px";

        height     = width = "1px";

        visibility = "hidden";

      }

      document.body.appendChild(comet.connection);

 

    }

  },

 

  // this function will be called from backend.jsp

  printServerTime: function (time) {

    $('abc').innerHTML = time;

  },

 

  onUnload: function() {

    if (comet.connection) {

      comet.connection = false; // release the iframe to prevent problems with IE when reloading the page

    }

  }

}

Event.observe(window,'load',comet.initialize);

Event.observe(window, 'unload', comet.onUnload);

</script>

 

总结一下,只能说现在的浏览器差别很大,想用一套代码适应所有的浏览器几乎是不可能。所以我觉,

一、为不同的浏览器定制不同的客户代码 

二、是用long polling方式开发,可以达到代码基本一致

有什么不对的欢迎讨论,有啥好的经验也欢迎交流:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值