要实现一个基于Streaming模式的comet,比较通用的办法就是使用Iframe来实现


但iframe有一个比较大的问题,浏览器中的进度条会一直停留在某个地方,显示正在加载


Google的工程师们,包装了一个js对象,在IE下使用htmlfile,Firefox下嵌套Iframe解决了这个问题


测试代码如下,Client端页面代码:



折叠复制代码




  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

  2. <htmlxmlns="http://www.w3.org/1999/xhtml">

  3. <head>

  4. <title>Comet demo</title>

  5. <metahttp-equiv="Content-Type"content="text/html; charset=utf-8"/>

  6. <scripttype="text/javascript"src="prototype.js"></script>

  7. </head>

  8. <body>

  9. <divid="abc">The server time will be shown here</div>

  10. <scripttype="text/javascript">

  11. var comet= {

  12. connection : false,

  13. iframediv : false,

  14. initialize: function() {

  15. var userAgent=navigator.userAgent.toLowerCase();

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

  17. // For IE browsers

  18. comet.connection=newActiveXObject("htmlfile");

  19. comet.connection.open();

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

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

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

  23. comet.connection.close();

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

  25. comet.connection.appendChild(comet.iframediv);

  26. cometcomet.connection.parentWindow.comet= comet;

  27. comet.iframediv.innerHTML="<iframe id='comet_iframe' src='./ysz_1.jsp'></iframe>";

  28. }


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

  30. // For Firefox browser

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

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

  33. with (comet.connection.style) {

  34. left=top= "-100px";

  35. height=width= "1px";

  36. visibility="hidden";

  37. display='none';

  38. }

  39. comet.iframediv pan>=document.createElement('iframe');

  40. comet.iframediv.setAttribute('src', './ysz_1.jsp');

  41. comet.connection.appendChild(comet.iframediv);

  42. document.body.appendChild(comet.connection);

  43. }


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

  45. // for other browsers

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

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

  48. comet.connection.setAttribute('src', './ysz_1.jsp');

  49. with (comet.connection.style) {

  50. position="absolute";

  51. left=top= "-100px";

  52. height=width= "1px";

  53. visibility="hidden";

  54. }

  55. document.body.appendChild(comet.connection);

  56. }

  57. },


  58. // this function will be called from backend.jsp

  59. printServerTime: function (time) {

  60. $('abc').innerHTML=time;

  61. },


  62. onUnload: function() {

  63. if (comet.connection) {

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

  65. }

  66. }

  67. }

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

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

  70. </script>

  71. </body>

  72. </html>




Server端jsp代码:



折叠复制代码




  1. <%@ pagelanguage="java"contentType="text/html;charset=UTF-8"

  2. pageEncoding="UTF-8"%>

  3. <%@pageimport="java.util.Date"%>

  4. <%

  5. response.setHeader("Cache-Control", "no-store");

  6. response.setHeader("Pragma", "no-cache");

  7. response.setDateHeader("Expires", 0);

  8. out.flush();

  9. %>

  10. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

  11. <htmlxmlns="http://www.w3.org/1999/xhtml">

  12. <head>

  13. <title>Comet backend</title>

  14. <metahttp-equiv="Content-Type"content="text/html; charset=UTF-8"/>

  15. </head>

  16. <body>


  17. <scripttype n>="text/javascript">

  18. // KHTML browser don't share javascripts between iframes

  19. var is_khtml=navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");

  20. if (is_khtml)

  21. {

  22. var prototypejs=document.createElement('script');

  23. prototypejs.setAttribute('type','text/javascript');

  24. prototypejs.setAttribute('src','prototype.js');

  25. var head=document.getElementsByTagName('head');

  26. head[0].appendChild(prototypejs);

  27. }

  28. // load the comet object

  29. //alert(window.parent.comet)

  30. var comet=window.parent.comet;

  31. </script>

  32. <%


  33. for(int i=0; i<10; i++){

  34. out.println("<scripttype='text/javascript'>");

  35. out.println("comet.printServerTime('" + (new Date()) + "');");

  36. out.println("</script>");

  37. out.flush();

  38. Thread.sleep(1000);

  39. }

  40. %>


  41. </body>

  42. </html>




以上代码,在Tomcat里测试正常,可以看到页面内容在不断变化,但如果用nginx反向代理后,页面就不能实时变化,而是最后load完了才变化


查了好久原因,才发现,nginx的proxy默认会Buffer后端Server的响应内容,导致Client端不能实时更新,解决很简单,把buffer给关闭就可以了:



折叠复制代码




  1. proxy_buffering off;




但在Resin里面,上述代码仍旧没有测试通过,页面无法实时更新,暂时还没有找到原因


但Resin自己也提供了一套comet的解决方案,参见这里