使用Iframe来实现Streaming模式的Comet
要实现一个基于Streaming模式的comet,比较通用的办法就是使用Iframe来实现
但iframe有一个比较大的问题,浏览器中的进度条会一直停留在某个地方,显示正在加载
Google的工程师们,包装了一个js对象,在IE下使用htmlfile,Firefox下嵌套Iframe解决了这个问题
测试代码如下,Client端页面代码:
折叠复制代码
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
- <htmlxmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title>Comet demo</title>
- <metahttp-equiv="Content-Type"content="text/html; charset=utf-8"/>
- <scripttype="text/javascript"src="prototype.js"></script>
- </head>
- <body>
- <divid="abc">The server time will be shown here</div>
- <scripttype="text/javascript">
- var comet= {
- connection : false,
- iframediv : false,
- initialize: function() {
- var userAgent=navigator.userAgent.toLowerCase();
- if (/msie/.test(userAgent) && !/opera/.test(userAgent)) {
- // For IE browsers
- comet.connection=newActiveXObject("htmlfile");
- comet.connection.open();
- comet.connection.write("<html>");
- comet.connection.write("<script>document.domain='"+document.domain+"';</script>");
- comet.connection.write("</html>");
- comet.connection.close();
- cometcomet.iframediv= comet.connection.createElement("div");
- comet.connection.appendChild(comet.iframediv);
- cometcomet.connection.parentWindow.comet= comet;
- comet.iframediv.innerHTML="<iframe id='comet_iframe' src='./ysz_1.jsp'></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 pan>=document.createElement('iframe');
- comet.iframediv.setAttribute('src', './ysz_1.jsp');
- 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', './ysz_1.jsp');
- 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>
- </body>
- </html>
Server端jsp代码:
折叠复制代码
- <%@ pagelanguage="java"contentType="text/html;charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@pageimport="java.util.Date"%>
- <%
- response.setHeader("Cache-Control", "no-store");
- response.setHeader("Pragma", "no-cache");
- response.setDateHeader("Expires", 0);
- out.flush();
- %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
- <htmlxmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title>Comet backend</title>
- <metahttp-equiv="Content-Type"content="text/html; charset=UTF-8"/>
- </head>
- <body>
- <scripttype n>="text/javascript">
- // KHTML browser don't share javascripts between iframes
- var is_khtml=navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");
- if (is_khtml)
- {
- var prototypejs=document.createElement('script');
- prototypejs.setAttribute('type','text/javascript');
- prototypejs.setAttribute('src','prototype.js');
- var head=document.getElementsByTagName('head');
- head[0].appendChild(prototypejs);
- }
- // load the comet object
- //alert(window.parent.comet)
- var comet=window.parent.comet;
- </script>
- <%
- for(int i=0; i<10; i++){
- out.println("<scripttype='text/javascript'>");
- out.println("comet.printServerTime('" + (new Date()) + "');");
- out.println("</script>");
- out.flush();
- Thread.sleep(1000);
- }
- %>
- </body>
- </html>
以上代码,在Tomcat里测试正常,可以看到页面内容在不断变化,但如果用nginx反向代理后,页面就不能实时变化,而是最后load完了才变化
查了好久原因,才发现,nginx的proxy默认会Buffer后端Server的响应内容,导致Client端不能实时更新,解决很简单,把buffer给关闭就可以了:
折叠复制代码
- proxy_buffering off;
但在Resin里面,上述代码仍旧没有测试通过,页面无法实时更新,暂时还没有找到原因
但Resin自己也提供了一套comet的解决方案,参见这里