Javascript 在 Chrome 中加载 (readyState==3) 时的 XmlHttpRequest.responseText
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3880381/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
XmlHttpRequest.responseText while loading (readyState==3) in Chrome
提问by Jaroslav Moravec
I am trying to "streaming" (from server to client) in Javascript by ajax (by XmlHttpRequest (=xhr). I am using modified handleResponse function described in Cross-browser implementation of "HTTP Streaming" (push) AJAX pattern
我正在尝试通过ajax(通过XmlHttpRequest(=xhr)在Javascript中“流式传输”(从服务器到客户端)。我正在使用“HTTP Streaming”(推送)AJAX模式的跨浏览器实现中描述的修改后的handleResponse函数
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;
}
With php script, which flushes me data (without ajax it really flushes data to browser while progressing)
使用 php 脚本,它会刷新我的数据(如果没有 ajax,它会在处理过程中真正将数据刷新到浏览器)
I have no problem in Firefox, but Google Chrome and IE give me an empty responseText while xhr.readyState equals to 3. I found that problem described in the Internet, but it didn't give me any solution.
我在 Firefox 中没有问题,但是 Google Chrome 和 IE 给了我一个空的 responseText 而 xhr.readyState 等于 3。我在互联网上发现了这个问题,但它没有给我任何解决方案。
Do you know, how to pass by this implementation problem in Chrome? (w3c says, that responseText can't be NULL in readyState==3 - Chrome implemented this rule, but gives only empty string)
你知道吗,如何在 Chrome 中绕过这个实现问题?(w3c 说,在 readyState==3 中 responseText 不能为 NULL - Chrome 实现了这个规则,但只给出空字符串)
And if you don't know, do you know any working solution in some products? (opensource frameworks, librararies etc.)
如果您不知道,您是否知道某些产品中的任何可行解决方案?(开源框架、库等)
Thanks a lot for your ideas.
非常感谢您的想法。
Edit:The workaround is in creating iframe, call the script to iframe and flush data here and grab data by javascript from iframe. But this is not ajax solution. I really would like to see pure ajax solution.
编辑:解决方法是创建 iframe,将脚本调用到 iframe 并在此处刷新数据,然后通过 iframe 中的 javascript 抓取数据。但这不是ajax解决方案。我真的很想看到纯 ajax 解决方案。
回答by Andrew
Chrome has a bug where it will only populate xhr.responseText after a certain number of bytes has been received. There are 2 ways to get around this,
Chrome 有一个错误,它只会在收到一定数量的字节后才填充 xhr.responseText。有两种方法可以解决这个问题,
Set the content type of the return to "application/octet-stream"
设置返回的内容类型为“application/octet-stream”
or
或者
Send a prelude of about 2kb to prep the handler.
发送大约 2kb 的前奏以准备处理程序。
Either of these methods should make chrome populate the responseText field when readyState == 3.
当 readyState == 3 时,这些方法中的任何一个都应该使 chrome 填充 responseText 字段。
IE7/8 on the other hand can't do it, you need to resort to long polling or use the cross domain trick with XDomainRequest in IE8, a la MS
另一方面,IE7/8 不能这样做,你需要求助于长轮询或在 IE8 中使用 XDomainRequest 的跨域技巧,la MS
回答by PleaseStand
Have you considered using WebSocketsor server-sent events?
您是否考虑过使用WebSockets或服务器发送的事件?
Most major browsersnow support the WebSocket protocol, though if your site needs to work in IE 9 or older, or in Android Browser 4.3 or older, you would have to keep the code that uses XMLHttpRequest as a fallback.
大多数主要浏览器现在都支持 WebSocket 协议,但如果您的网站需要在 IE 9 或更旧版本或 Android 浏览器 4.3 或更旧版本中工作,则必须保留使用 XMLHttpRequest 作为后备的代码。
Most of these browsersalso support a feature called server-sent events, which unlike WebSockets, can be implemented on the server using a traditional HTTP daemon and CGI/PHP script, though only provides one-way communication.
这些浏览器中的大多数还支持称为服务器发送事件的功能,与 WebSockets 不同,它可以使用传统的 HTTP 守护程序和 CGI/PHP 脚本在服务器上实现,但仅提供单向通信。
回答by Tobia
To expand on Andrew's answer, this is the cross-browser solution I came up with.
为了扩展安德鲁的答案,这是我想出的跨浏览器解决方案。
Works correctly in 99% of browsers, namely IE ≥ 8, Chrome, Firefox, and Safari, sending incremental events as soon as data is received by the browser (but see the notes below.)
在 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 will start populating responseText after 2kB of data, so if that's not ok, you should send an initial padding of 2kB.
IE 8-9 将在 2kB 数据后开始填充 responseText,所以如果这不行,你应该发送一个 2kB 的初始填充。
Chrome needs either that, or Content-Type: application/octet-stream
.
Chrome 需要那个,或者Content-Type: application/octet-stream
.
回答by Frank
Well, unfortunately every part of XmlHttpRequest (or any web standards) isn't fully implemented in all browsers. But you have several other options for HTTP Streaming:
Wikipedia: Push technology
Wikipedia: Comet (programming)Wikipedia: Web Sockets(experimental, low browser support)
好吧,不幸的是 XmlHttpRequest(或任何 Web 标准)的每个部分都没有在所有浏览器中完全实现。但是对于 HTTP 流,您还有其他几种选择:
Wikipedia:推送技术
Wikipedia:Comet(编程)Wikipedia:Web Sockets(实验性,低浏览器支持)
I saw in your comment that you would like it to be pure AJAX, but I like to suggest possible alternate ways to solutions. You could use a JavaApplet where possible or a Flash Object. For the latter you won't need a flashy and expensive IDE, you can use Haxeto create Flash/SWF files and you will feel pretty comfortable with it as you know JavaScript.
我在您的评论中看到您希望它是纯 AJAX,但我想建议可能的替代解决方案。您可以尽可能使用 JavaApplet 或 Flash 对象。对于后者,您将不需要华丽且昂贵的 IDE,您可以使用Haxe创建 Flash/SWF 文件,并且您会因为了解 JavaScript 而对它感到非常自在。
Here is a Flash/Neko chat examplethat probably can be adopted to other platforms and usages as well.
这是一个Flash/Neko 聊天示例,它可能也适用于其他平台和用途。
I wish you best of good luck.
我祝你好运。
回答by Fordi
This worked for me for Chrome, but not IE:
这对我适用于 Chrome,但不适用于 IE:
[test.php]:
[测试.php]:
<?php
Header('Content-type: text/plain');
while (1) {
echo str_pad('test: '.mt_rand(1000,9999), 2048, ' ');
flush();
sleep(1);
}
[test.html]:
[测试.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>
YMMV.
天啊。
回答by radio4fan
As Jaroslav Moravec said, if you set the content-type in the header of the stream to application/x-javascript it works in Safari, Chrome and Firefox.
正如 Jaroslav Moravec 所说,如果您将流标头中的 content-type 设置为 application/x-javascript,它可以在 Safari、Chrome 和 Firefox 中使用。
I have not tested IE.
我没有测试过IE。
回答by Serge Profafilecebook
Setting the content type of the return to "application/octet-stream" as suggested by Andrew was a great solution. Plus you should use XDomainRequest on IE.
按照 Andrew 的建议将返回的内容类型设置为“application/octet-stream”是一个很好的解决方案。另外,您应该在 IE 上使用 XDomainRequest。
To read the data as they come, you should just use an infinite loop (that stops when readystate = 4 or XDomainRequest.onLoad has been called) with a timeout.
要在数据到来时读取数据,您应该使用带有超时的无限循环(当 readystate = 4 或 XDomainRequest.onLoad 被调用时停止)。
Here's how I would do it:
这是我将如何做到的:
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;
}
}
Note: some says using eval is risky, I claim that's not where any risk really come from.
注意:有人说使用 eval 是有风险的,我声称这并不是任何风险的真正来源。
回答by Ravindra Sane
try using the responseStream/responseBody property when in IE. I was thinking of doing a similar thing once and ran into the same problem. Unfortunately neither are w3c specs
在 IE 中尝试使用 responseStream/responseBody 属性。我曾经想过做类似的事情,但遇到了同样的问题。不幸的是,w3c 规范也不是
http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute
http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute
回答by tobyodavies
As i understand it, making partial text available on readyState 3 is a non-standard firefox only behaviour that is simply not possible to directly emulate in other browsers, what you might want to do instead is make multiple sequential requests for small chunks of the data rather than one 'streaming' request
据我了解,在 readyState 3 上提供部分文本是一种非标准的仅限 Firefox 的行为,在其他浏览器中根本无法直接模拟,您可能想要做的是对小块数据发出多个顺序请求而不是一个“流媒体”请求
回答by Nivas
The URLyou are submitting the request to - is it part of your domain?
您提交请求的 URL - 它是您域的一部分吗?
It coulld be because of the same origin policy.
这可能是因为同源策略。
See this questionand possible ways to circumvent it(and this article).