【问题标题】:Get a response in chunks from express in browser从浏览器中的 express 获取块的响应
【发布时间】:2021-09-30 09:45:40
【问题描述】:

我正在为一些长时间运行的服务器端任务(最多几分钟)构建一个进度条,我想要一种显示任务进度的方法。我可以使用 WebSockets 或按间隔轮询,但我不想跟踪每个任务。相反,我想使用长轮询并将进度更新写入流。

这是路由在服务器上的样子的演示

app.get('/test', (req, res) => {
    let num = 0;
    const interval = setInterval(() => res.write(num++ + ' '), 300);
    setTimeout(() => {
        clearInterval(interval);
        res.send();
    }, 5000);
});

使用-N 在该端点上执行 cURL 效果很好,但是在浏览器中实现它时遇到了一些问题。

我尝试过这样的获取:

const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
    const { done, value } = await reader.read();
        if (done)
            break;  
    console.log(decoder.decode(value));
}

这在 Chrome 上运行得很好,但在 Firefox 上却不行,正如你所见,这里不支持它:

https://caniuse.com/mdn-api_windoworworkerglobalscope_fetch_streaming_response_body

不过,我尝试了不同的方法,这次是使用 XHR

const xhr = new XMLHttpRequest()
xhr.open("GET", url)
xhr.onprogress = function () {
    console.log(xhr.responseText);
};
xhr.send();

这在 Firefox 中完美运行,但在 Chrome 中,onProgress 事件仅在整个请求被处理后才会触发。我也尝试过使用onReadyStateChange,但这会导致同样的问题。

>_ 在任一浏览器中更新时,我如何分块读取这些该死的数据?我想我可以试试 Axios,但我真的需要这个吗?

编辑:值得一提的是 Chrome 和 Firefox 似乎以不同的方式处理获取行为。使用 Chrome,我可以在 fetch 完成之前使用 fetch 对象,所以我这样做了

const response = await fetch(url);
console.log("Preflight complete, fetch is not done though");

但在 Firefox 中,控制台日志在获取解决之前不会执行。这就是为什么我认为我不能在 Firefox 中使用响应正文,但我可以使用 Chrome。

【问题讨论】:

  • 奇怪 - 获取流响应正文似乎在 Firefox 90 中工作 - 不,我没有弄乱任何标志 - 根据 MDN 自 Firefox 65 以来已经这样做了 - 是什么让你认为它不起作用,你试过吗?你在firefox中遇到了什么问题
  • 好吧,@Bravo,我尝试使用 fetch 示例,但它根本不起作用。 XHR 示例在 FF 中运行良好。我也尝试启用这些标志,但这对我没有任何好处,这不仅是我的浏览器需要处理的事情。
  • @Bravo 我想这取决于您所说的“工作”是什么意思。我没有像 OP 那样进行测试,但从技术上讲,在获取完成后流只触发一个事件也“工作”,因为你没有丢失任何数据。
  • @slebetman 是的,我得到了所有的数据,但是只有在服务器完成请求之后,而不是在创建请求之后的后续事件中。
  • @SethPainter - 是的,你确实说过关于 chrome 和 onprogress - 我实际上指的是获取流响应正文

标签: javascript express xmlhttprequest fetch long-polling


【解决方案1】:

根据这个 GitHub 问题:

https://github.com/ratpack/ratpack/issues/443#issuecomment-59621215

这是一个 Chrome/Webkit 错误。从text/plain 以外的任何地方更改请求的Content-Type 使其与Chrome 上的XHR 一起工作。因此,如果我将服务器响应更改为

app.get('/test', (req, res) => {
    let num = 0;
    let interval = setInterval(() => res.write(num++ + ' '), 300);
    // THIS IS A DUMB HACK TO GET CHROME TO PLAY NICE X_X
    res.setHeader('Content-Type', 'text/html');
    setTimeout(() => {
        clearInterval(interval);
        res.send();
    }, 5000);
});

令人震惊的是,这似乎也解决了在 Firefox 中使用未修改标志获取流的问题。我想我现在会使用XHR 方法,只是因为它更兼容,但是,由于每个新块都是单独处理的,因此获取版本更容易使用。

AHHHHHHHHH

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    • 2016-11-19
    • 2015-02-12
    • 2011-06-24
    • 2018-06-04
    • 2021-05-20
    • 1970-01-01
    相关资源
    最近更新 更多