我试图通过ajax(通过XmlHttpRequest(= xhr)在Javascript中“流式传输”(从服务器到客户端)。我使用的是修改后的handleResponse函数 Cross-browser implementation of "HTTP Streaming" (push) AJAX pattern
function handleResponse() {
if (http.readyState != 4 && http.readyState != 3)
return;
if (http.readyState == 3 && http.status != 200)
return;
if (http.readyState == 4 && http.status != 200) {
clearInterval(pollTimer);
inProgress = false;
}
// In konqueror http.responseText is sometimes null here...
if (http.responseText === null)
return;
while (prevDataLength != http.responseText.length) {
if (http.readyState == 4 && prevDataLength == http.responseText.length)
break;
prevDataLength = http.responseText.length;
var response = http.responseText.substring(nextLine);
var lines = response.split('\n');
nextLine = nextLine + response.lastIndexOf('\n') + 1;
if (response[response.length-1] != '\n')
lines.pop();
for (var i = 0; i < lines.length; i++) {
// ...
}
}
if (http.readyState == 4 && prevDataLength == http.responseText.length)
clearInterval(pollTimer);
inProgress = false;
}
使用php脚本,它可以刷新数据(没有ajax,它会在进行过程中将数据刷新到浏览器中)
我在Firefox中没有问题,但谷歌Chrome和IE给我一个空的responseText而xhr.readyState等于3.我发现在互联网上描述了这个问题,但它没有给我任何解决方案。
您知道吗,如何在Chrome中解决此实施问题? (w3c说,readyState中的responseText不能为NULL == 3 - Chrome实现了这个规则,但只给出了空字符串)
如果你不知道,你知道某些产品的工作解决方案吗? (开源框架,图书馆等)
非常感谢你的想法。
修改 解决方法是创建iframe,将脚本调用到iframe并在此处刷新数据,并通过jrame从iframe获取数据。但这不是ajax解决方案。我真的很想看到纯粹的ajax解决方案。
答案 0 :(得分:17)
Chrome有一个错误,它只会在收到一定数量的字节后填充xhr.responseText。有两种方法可以解决这个问题,
将返回的内容类型设置为“application / octet-stream”
或
发送约2kb的前奏来准备处理程序。
当readyState == 3时,这些方法中的任何一个都应该使chrome填充responseText字段。
另一方面IE7 / 8无法做到,你需要求助于长时间轮询或在IE8中使用XDomainRequest的跨域技巧,la MS答案 1 :(得分:3)
您是否考虑过使用WebSockets或server-sent events?
Most major browsers现在支持WebSocket协议,但如果您的网站需要在IE 9或更早版本中运行,或者在Android浏览器4.3或更早版本中运行,则必须保留使用XMLHttpRequest作为后备的代码。 / p>
Most of these browsers还支持一个名为服务器发送事件的功能,它与WebSockets不同,可以使用传统的HTTP守护程序和CGI / PHP脚本在服务器上实现,但只提供一个 - 通信。
答案 2 :(得分:3)
为了扩展安德鲁的答案,这是我提出的跨浏览器解决方案。
在99%的浏览器中正常运行,即IE≥8,Chrome,Firefox和Safari ,一旦浏览器收到数据就会发送增量事件(但请参阅下面的注释。)
if (/MSIE [8-9]/.test(navigator.appVersion)) {
var get = new XDomainRequest()
get.onprogress = handleData
get.onload = handleData
} else {
var get = new XMLHttpRequest()
get.onreadystatechange = handleData
}
get.open('get', '/example/url')
get.send()
function handleData() {
if (get.readyState != null && (get.readyState < 3 || get.status != 200)) {
return
}
// process incremental data found in get.responseText
}
IE 8-9将在2kB数据后开始填充responseText,所以如果不行,你应该发送一个2kB的初始填充。
Chrome需要或Content-Type: application/octet-stream
。
答案 3 :(得分:2)
嗯,不幸的是,XmlHttpRequest(或任何Web标准)的每个部分都没有在所有浏览器中完全实现。但是您还有其他几种HTTP Streaming选项:
Wikipedia: Push technology
Wikipedia: Comet (programming)
Wikipedia: Web Sockets(实验性,低浏览器支持)
我在你的评论中看到你希望它是纯粹的AJAX,但我想建议可能的替代解决方案。您可以在可能的情况下使用JavaApplet或使用Flash对象。对于后者,您不需要华而不实且昂贵的IDE,您可以使用Haxe创建Flash / SWF文件,并且您会对JavaScript感到非常熟悉。
这是Flash/Neko chat example,可能也可以用于其他平台和用法。
祝你好运。
答案 4 :(得分:1)
在IE中尝试使用responseStream / responseBody属性。我想过做一次类似的事情并遇到同样的问题。不幸的是w3c规格都不是
http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute
答案 5 :(得分:1)
据我所知,在readyState 3上提供部分文本是一种非标准的firefox行为,根本无法直接在其他浏览器中模拟,你可能想要做的是对小块进行多个顺序请求数据而不是一个“流媒体”请求
答案 6 :(得分:1)
这适用于Chrome,但不适用于IE:
[test.php的]:
<?php
Header('Content-type: text/plain');
while (1) {
echo str_pad('test: '.mt_rand(1000,9999), 2048, ' ');
flush();
sleep(1);
}
[的test.html]:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Stream test</title>
<meta charset="UTF-8" />
<script type="text/javascript">
function xmlHttpRequest() {
return (function (x,y,i) {
if (x) return new x();
for (i=0; i<y.length; y++) try {
return new ActiveXObject(y[i]);
} catch (e) {}
})(
window.XMLHttpRequest,
['Msxml2.XMLHTTP','Microsoft.XMLHTTP']
);
};
function stream(url) {
// Declare the variables we'll be using
var xmlHttp = xmlHttpRequest();
xmlHttp.open("GET", url, true);
var len = 0;
xmlHttp.onreadystatechange = function() {
if (xmlHttp.status == 200 && xmlHttp.readyState >=3) {
var text = xmlHttp.responseText;
text = text.substr(len, text.length-len);
len = xmlHttp.responseText.length;
console.log(text);
}
}
xmlHttp.send(null);
}
stream('/test.php');
</script>
</head>
<body>
</body>
</html>
因人而异。
答案 7 :(得分:1)
正如Jaroslav Moravec所说,如果你将流的标题中的内容类型设置为application / x-javascript,它可以在Safari,Chrome和Firefox中使用。
我没有测试IE。
答案 8 :(得分:1)
按照Andrew的建议将返回的内容类型设置为“application / octet-stream”是一个很好的解决方案。 另外,你应该在IE上使用XDomainRequest。
要读取数据,您应该使用无限循环(当readystate = 4或XDomainRequest.onLoad被调用时停止)并且超时。
我将如何做到这一点:
var i = 0;
var returnValue = function() {
if (!finished) {
setTimeout(returnValue, 100);
}
var resp = ajax.responseText;
var newI = resp.lastIndexOf(";") + 1;
if (newI > i) {
var lines = resp.substring(i, newI).split(";");
for (var x = 0; x < lines.length; x++) {
eval(lines[x]);
}
i = newI;
}
}
注意:有人说使用eval是有风险的,我声称这不是真正来自风险的地方。
答案 9 :(得分:0)
您提交请求的网址是 - 它是您网域的一部分吗?
这可能是因为same origin policy。
答案 10 :(得分:0)
一旦我使用safari遇到这个问题(从未测试过使用chrome,也许有同样的问题(chrome / safari都使用相同的渲染引擎(据我所知) - 不知道js-parts ))。我从来没有找到解决方案来解决这个问题,但由于它是公司范围的内部网中的一个小应用程序,因此不支持safari(ff是默认浏览器,并且ff正常工作)并不是一个大问题。 / p>