gpt4 book ai didi

javascript - 如何在数据到达之前检查 XMLHttpRequest 连接是否已建立

转载 作者:塔克拉玛干 更新时间:2023-11-02 21:37:57 26 4
gpt4 key购买 nike

我正在使用 EventSource 实现一些服务器端事件,我需要知道何时建立 EventSource 连接以及服务器响应初始 200 OK,然后我可以开始执行一些其他请求,这些请求最终会导致服务器通过 EventSource 发送消息。

我实际上使用了这个 polyfill https://github.com/AlexGalays/EventSource它在内部使用 XMLHttpRequest。

问题:当服务器发送 200 个 OK + header 时,onreadystatechange 没有被触发(xhr.readyState 仍然是 1 )。这是与任何 XHR 相关的普遍问题,而不仅仅是 EventSource。

示例 PHP 服务器:

<?php
sleep(5); // our actual implementation does some non-trivial startup here
// send 200 OK + headers, but no data
flush();

sleep(5);
echo "bye";

示例 - 客户端:

<script>
xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => console.log(`readystate = ${xhr.readyState}`);
xhr.open('GET', 'http://localhost/longpoll.php');
xhr.send();
</script>

预期行为:

  • 就绪状态 = 1(打开)
  • 5秒延迟
  • 就绪状态 = 2(收到 header )
  • 5秒延迟
  • 就绪状态 = 3(加载中)
  • 就绪状态 = 4(完成)

实际行为:

  • 就绪状态 = 1(打开)
  • 延迟 10 秒
  • 就绪状态 = 2(收到 header )
  • 就绪状态 = 3(加载中)
  • 就绪状态 = 4(完成)

在最新的 Chrome (77) 和 Firefox (69) 中测试,两者的行为相同。

当我在 Chrome 开发工具 网络 选项卡中观察连接时,我确实在前 5 秒延迟后看到了响应 header 和状态代码(请参阅 https://youtu.be/sIgQnbfwxjM ).这意味着浏览器在前 5 秒后真正接收到 header 并更新连接状态,但 JavaScript 未被确认。

这能以某种方式解决吗?还是某些安全限制阻止我在此阶段获取更新的连接状态?

最佳答案

默认情况下,Chrome 和其他浏览器会缓冲 XMLHttpRequest 的整个响应( header 和正文)。所以没有简单的选项可以先检查 header ,然后使用 XMLHttpRequest 获取正文。唯一的解决方案是将响应作为一个流/ block 来处理,而不是一个单一的响应。在 Firefox 中有 "moz-chunked-arraybuffer" for xhr.responseType 但它是 removed .谷歌浏览器在某个时候实现了 xhr.responseType "stream" ( as experimental ),但它一直是 dropped in favor of whatwg Streams .今天最简单fetch API在大多数现代浏览器中,我们可以获取没有正文的响应 header (如果服务器已发送)。在 Chrome 77 中测试:

let response = await fetch('http://localhost:9615/');

if (response.ok) {
console.log('status code:', response.status);
let text = await response.text();
console.log('text', text);
} else {
console.error('HTTP-Error:', response.status);
}

您也可以使用直接提到的 whatwg Streams ( ReadableStream ),如下所示:

fetch("http://localhost:9615/").then((response) => {
const reader = response.body.getReader();
const stream = new ReadableStream({
start(controller) {
console.log('status code:', response.status);
function push() {
reader.read().then(({ done, value }) => {
console.log('read', value);
if (done) {
console.log('done');
controller.close();
return;
}

controller.enqueue(value);
push();
});
};

push();
}
});

return new Response(stream, { headers: { "Content-Type": "text/html" } });
});

作为测试服务器,我使用了以下代码 (NodeJS):

const http = require('http');

http.createServer(function (req, res) {
setTimeout(() => {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.flushHeaders();
setTimeout(() => {
res.write("some content");
res.end();
}, 3000);
}, 3000);
}).listen(9615);

在这两种解决方案(Fetch API 和 ReadableStream)中,您将在前 3000 毫秒后获得状态代码:200,并在接下来的 3000 毫秒后获得其余响应。

不幸的是Streams浏览器尚未广泛支持,但 here是一个 polyfill。另见 this .

关于javascript - 如何在数据到达之前检查 XMLHttpRequest 连接是否已建立,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58324522/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com