在ReactJs中使用EventSource消费事件流时,获取net :: ERR_INCOMPLETE_CHUNKED_ENCODING 200

时间:2019-06-04 19:34:08

标签: node.js reactjs google-chrome-devtools server-sent-events eventsource

我有一个非常简单的节点服务,它公开了一个旨在使用服务器发送事件(SSE)连接的终结点,还有一个非常基本的ReactJs客户端通过EventSource.onmessage对其进行使用。

首先,当我在updateAmountState(Chrome Dev)中设置调试点时,看不到它。

其次,我得到了net :: ERR_INCOMPLETE_CHUNKED_ENCODING 200(确定)。根据{{​​3}},“ Chrome中的ERR_INCOMPLETE_CHUNKED_ENCODING通常表示在写入响应主体的过程中,应用程序抛出了未捕获的异常”。然后,我检查了服务器端,看是否发现任何错误。好吧,我在两个setTimeout(()=> {...中的server.js中的几个地方都设置了断点,我看到它是定期运行的。我希望每行只运行一次。所以前端似乎是尝试永久调用后端并获得一些错误。

ReactJs中的整个应用程序以及NodeJs中的服务器的整个应用程序都可以在https://github.com/aspnet/KestrelHttpServer/issues/1858中找到。

后端:

const http = require("http");

http
  .createServer((request, response) => {
    console.log("Requested url: " + request.url);

    if (request.url.toLowerCase() === "/coins") {
      response.writeHead(200, {
        Connection: "keep-alive",
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache"
      });

      setTimeout(() => {
        response.write('data: {"player": "Player1", "amount": "90"}');
        response.write("\n\n");
      }, 3000);

      setTimeout(() => {
        response.write('data: {"player": "Player2", "amount": "95"}');
        response.write("\n\n");
      }, 6000);
    } else {
      response.writeHead(404);
      response.end();
    }
  })
  .listen(5000, () => {
    console.log("Server running at http://127.0.0.1:5000/");
  });

前端:

import React, { Component } from "react";
import ReactTable from "react-table";
import "react-table/react-table.css";
import { getInitialCoinsData } from "./DataProvider";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: getInitialCoinsData()
    };

    this.columns = [
      {
        Header: "Player",
        accessor: "player"
      },
      {
        Header: "Amount",
        accessor: "amount"
      }
    ];
    this.eventSource = new EventSource("coins");
  }


  componentDidMount() {
    this.eventSource.onmessage = e =>
      this.updateAmountState(JSON.parse(e.data));
  }

  updateAmountState(amountState) {
    let newData = this.state.data.map(item => {
      if (item.amount === amountState.amount) {
        item.state = amountState.state;
      }
      return item;
    });

    this.setState(Object.assign({}, { data: newData }));
  }

  render() {
    return (
      <div className="App">
        <ReactTable data={this.state.data} columns={this.columns} />
      </div>
    );
  }
}

export default App;

我在chrome上看到的异常:

https://github.com/jimisdrpc/hello-pocker-coins

所以我的直接问题是:为什么我得到ERR_INCOMPLETE_CHUNKED_ENCODING 200?我在后端还是前端缺少某些东西?

一些提示可能对我有帮助:

  1. 为什么我根本没有使用websocket,为什么我看到websocket处于挂起状态?我知道基本的区别(websocket是双向的,从前到后,从后到前,这是一个不同的协议,而SSE在http上运行并且仅从前到后)。但是我根本不打算使用websocket。 (请参见打印屏幕下方的蓝线)

  2. 为什么我看到0字节和236字节的事件源都失败了。我了解当我编写“ this.eventSource = new EventSource(“ coins”);“时,事件源正是我要使用的源。 (请参阅下面的打印屏幕中的阅读行)

  3. 至少对我来说很奇怪,有一段时间,当我杀死发球时,我看到了updateAmountState方法被唤醒。

  4. 如果在浏览器中调用localhost:5000 / coins,我可以看到服务器回答了响应(两个json字符串)。我可以假设我对服务器进行了正确的编码,并且错误在前端中是排他性的吗?

2 个答案:

答案 0 :(得分:4)

这是您问题的答案。

  1. 您看到的websocket正在运行,与您在此处发布的代码无关。它可能与您在应用程序中使用的另一个NPM软件包有关。通过查看网络请求中的标头,您也许可以弄清楚它的来源。
  2. eventsource请求失败的最可能原因是它们超时。在闲置两分钟后,Chrome浏览器将终止闲置的流。如果要保持活动状态,则需要添加一些代码,以至少每两分钟一次的时间将某些内容从服务器发送到浏览器。为了安全起见,最好每分钟发送一次。下面是您需要的示例。如果在服务器代码中的第二个setTimeout之后添加它,它应该可以满足您的需求。
const intervalId = setInterval(() => {
  res.write(`data: keep connection alive\n\n`);
  res.flush();
}, 60 * 1000);

req.on('close', () => {
  // Make sure to clean up after yourself when the connection is closed
  clearInterval(intervalId);
});
  1. 我不确定为什么有时会看到updateAmountState方法被调用。如果您不能始终看到它,则可能不是主要问题,但是如果服务器在完成之前停止运行,则可能有助于清理setTimeout。您可以通过将它们声明为变量,然后在关闭事件处理程序中将变量名传递给clearTimeout来实现此目的,类似于在上面的#2示例中对间隔所做的操作。
  2. 您的代码设置正确,并且您看到的错误是由于Chrome浏览器超时造成的。如果您想阻止错误的发生,请使用上述答案2中的代码。

答案 1 :(得分:1)

我自己不是Node.js专家,但是您似乎想念“'Connection':'keep-alive'”和其后的“ \ n”,即:

response es.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
});
response.write('\n');

请参见https://jasonbutz.info/2018/08/server-sent-events-with-node/。希望它能起作用!