关于在 Comet 应用中浏览器一直保持下载状态的问题

8 views
Skip to first unread message

沈崴

unread,
Aug 14, 2008, 12:12:44 AM8/14/08
to eurasia-users
在长连接中, 浏览器会一直处于下载状态。Eurasia3 的 Pushlet 接口
也存在这个问题, 这个 Albert Lee 和潘俊勇都有提到过。因为这个不属于
服务器的范畴, 所以对此 Eurasia3 核心不提供解决方案。

这里和大家分享一下我关于这个问题的解决方案, 作为补充。

在原理上, 这里使用目前大家都已经普遍在应用的方法, 就是利用 htmlfile
这个 ActiveX 组件来绕过 IE 浏览器的下载状态。在客户端大家都大同小异,
不过在服务器端 Eurasia3 使用的是 RPC 模式, 而不是常见的 Event 模式。
在 Eurasia3 中, 客户端将客户端的 JavaScript 函数开放到 __comet__
这个名字空间, 使服务器可以直接调用这个函数 (服务器 Python 脚本可以直接
跨语言调用浏览器上的 JavaScript 函数)。

我面向 FireFox 和 IE 分别编写了两个 Comet 函数。

FireFox 浏览器:

window.comet = function(url, disconnect) {
var xhr = new XMLHttpRequest(), find_begin = function() {
var pos = xhr.responseText.indexOf('<!--COMET BEGIN-->\r\n');
if(pos == -1) return -1;
xhr.pos = pos + 20;
return xhr.pos;

}, rpc = function() {
var pos = xhr.responseText.indexOf('//-->\r\n</script>\r\n',
xhr.pos);
if(pos == -1) return -1;
pos += 18;
try {
var range = document.createRange();
range.setStartBefore(document.body);
document.body.appendChild(range.createContextualFragment(
xhr.responseText.substring(xhr.pos, pos)));

} catch(e) { alert('ERROR:COMETRPC FOR GECKO, ERROR OCCURED'); }

xhr.pos = pos;
return pos;
};

xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if(xhr.readyState == 3 || xhr.readState == 4)
if(xhr.pos) while(rpc() != -1) continue;
else
if(find_begin() == -1) null;
else while(rpc() != -1) continue;

if(xhr.readyState == 4 && disconnect) disconnect();

}; xhr.send(null);

}; window.__comet__ = window;


IE 浏览器:

window.comet = function(url, disconnect) {
var hfile = new ActiveXObject('htmlfile');
hfile.open();
hfile.write('<html>\r\n<head></head>\r\n<body>\r\n<iframe
name="comet_iframe" ' +
'src="about:blank"></iframe>\r\n<script language="JavaScript">\r
\n<!' +
'--\r\n \r\n-->\r\n</' + 'script>\r\n</body>\r\n</html>');
hfile.close();
if(disconnect) hfile.body.onload = disconnect;
hfile.parentWindow.__comet__ = window;
hfile.comet_iframe.location.href = url;

};


使用 comet 函数:

function foo(s)
{
alert(s);
};

comet('http://xxx/xxx', ondisconnect)

comet 函数指向一个 Eurasia3 Pushlet controller 的地址。
Pushlet controller 可以直接调用该页面上的 JavaScript 函数:

from Eurasia.web import Pushlet
def controller(client):
browser = Pushlet(client)
browser.foo('hello world!')

如果长连接中断, 服务器会抛出 Disconnect 异常。而客户端会调用
ondisconnect 函数 (comet 函数的第二参数)。这意味着客户端不必
总是向服务器发送心跳包以确认长连接是否还在。

心跳是不需要的。

上面两个 Eurasia3 长连接的支持函数我也放在 njf 这个 JavaScript
库中 (svn):

http://code.google.com/p/njf/source/browse/trunk/njf.js?r=4

njf 是我编写的一套历史悠久并且长期在多个项目中付诸商用的
JavaScript 库。现在也已经进入开源发布过程了。该库目前只支持
Gecko 和 IE, 类似于 Konqueror、Opera 这些浏览器尚不能支持,
这是下一阶段的目标。

对于 Comet, 在 Eurasia3 中的接口是 Pushlet。不使用 Comet
这个名称的原因是认为这个名称和大多数 Java 概念一样过于哗众取宠。

不过既然目前 Comet 这个名称已经流行, 处于 Pythoner 尊重惯例
的习惯, 我将在下一个发布中将 Pushlet 更名为 Comet。

我可能会在 alpha5 或者 alpha6 版本里冷却 Eurasia 3.0.0
版本的特性。目前大部分 Eurasia 3.0.0 的接口都已经稳定。
另外除了 Comet 之外, 在 alpha5 里对 time.sleep 以及
urllib.urlopen 进行 stackless 转化的支持可能会被移出
Eurasia3 核心。这些移出的支持将会放在另一个较为合理的位置上。
而 Eurasia3 核心会更小更快。
Reply all
Reply to author
Forward
0 new messages