使用 HTML5 服务器事件和 Java Servlet 时如何防止 net::ERR_INCOMPLETE_CHUNKED_ENCODING?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26863972/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 03:25:21  来源:igfitidea点击:

How to prevent net::ERR_INCOMPLETE_CHUNKED_ENCODING when using HTML5 Server events and Java Servlets?

javagoogle-chromeservlet-3.0server-sent-events

提问by Chris

i just started to play around with Server Events and i run into a chrome error message i would like to understand. i searched the web real quick but didn't find an explanation so i guess i may do something terribly wrong.

我刚开始玩服务器事件,我遇到了一条我想了解的 chrome 错误消息。我很快在网上搜索,但没有找到解释,所以我想我可能做错了什么。

On the server side i have a simple servlet that accepts requests and creates a dummy event creator task:

在服务器端,我有一个简单的 servlet,它接受请求并创建一个虚拟事件创建者任务:

private Executor executor = Executors.newSingleThreadExecutor();

public void doGet(final HttpServletRequest request, final HttpServletResponse response)
{
  final AsyncContext asynCtx = request.startAsync(request, response);

  response.setHeader("Cache-Control", "no-cache");
  response.setContentType("text/event-stream");
  response.setCharacterEncoding("utf-8");

  executor.execute(() -> {
    boolean run = true;
    try
    {
      while (run)
      {
        final ServletResponse resp = asynCtx.getResponse();
        run = resp != null;

        if (resp != null)
        {
          System.out.println("pushing a server event.");
          final PrintWriter writer = asynCtx.getResponse().getWriter();
          writer.println("data: {time: " + System.currentTimeMillis() + "}\n");
          writer.flush();
        }
        else
        {
          System.out.println("stopping beeper, no response object available anymore.");
          break; // do not run anymore, we got no response
        }

        Thread.sleep(2000);
      }
    }
    catch (final Exception e)
    {
      e.printStackTrace();
    }
  });

}

on the client i simply:

在客户端我只是:

$(document).ready(function ()
{

   var source = new EventSource("/events");
   source.onmessage = function (event)
   {
     console.log("received event: " + JSON.stringify(event));
     document.getElementById("eventContainer").innerHTML += event.data + "<br/>";
   };

   console.log("start to receive events...")
});

when i load the HTML file it works fine, events are received and written to the console. But after 30 secondsi get an error message:

当我加载 HTML 文件时它工作正常,事件被接收并写入控制台。但是30 秒后,我收到一条错误消息:

GET [HttpOfLocalhost]/events net::ERR_INCOMPLETE_CHUNKED_ENCODING

GET [HttpOfLocalhost]/events net::ERR_INCOMPLETE_CHUNKED_ENCODING

why?

为什么?

the request than gets killed and a new one is started immediately so it doesn't kill the application but error messages on the console aren't nice.

该请求会被终止并立即启动一个新的请求,因此它不会终止应用程序,但控制台上的错误消息并不好。

screenshot of my developer console:

我的开发者控制台的屏幕截图:

enter image description here

在此处输入图片说明

request/resposne details:

请求/响应详细信息:

enter image description here

在此处输入图片说明

timing, this shows that it always occurs after 30 seconds:

计时,这表明它总是在 30 秒后发生:

enter image description here

在此处输入图片说明

Thanks!

谢谢!

采纳答案by Chris

Ok, so i couldn't stand still and look closer whats happening.

好吧,所以我不能停下来仔细观察发生了什么。

The AsyncContextobject has a setTimeout(...)method. Per default in my version of tomcat (Tomcat embedded 8) the value is set to 30,000 ms (30 seconds). That's exactly the duration after i got the net::ERR_INCOMPLETE_CHUNKED_ENCODINGerror in my chrome console.

AsyncContext对象具有的setTimeout(...)方法。在我的 tomcat 版本(嵌入式 Tomcat 8)中,默认值设置为 30,000 毫秒(30 秒)。这正是我在 Chrome 控制台中收到net::ERR_INCOMPLETE_CHUNKED_ENCODING错误后的持续时间。

i checked using:

我检查使用:

System.out.println("Current Timeout is: " + asynCtx.getTimeout() + " ms");

which showed:

其中显示:

Current Timeout is: 30000 ms

so to avoid the net:ERR message someone could set the timeout to 0. But than the event thread keeps running forever (unfortunately). Another solution, which i used, is to add a AsyncListenerto the AsyncContextand call the complete()method inside the onTimeout()method.

所以为了避免 net:ERR 消息,有人可以将超时设置为 0。但是事件线程永远运行(不幸的是)。另一种解决方案,这在我以前,是将添加AsyncListenerAsyncContext并调用完成()的内部方法onTimeout()方法。

from the API doc of the complete() method:

来自 complete() 方法的 API 文档:

Completes the asynchronous operation that was started on the request that was used to initialze this AsyncContext, closing the response that was used to initialize this AsyncContext. Any listeners of type AsyncListener that were registered with the ServletRequest for which this AsyncContext was created will be invoked at their onComplete method.

完成在用于初始化此 AsyncContext 的请求上启动的异步操作,关闭用于初始化此 AsyncContext 的响应。任何注册到为其创建此 AsyncContext 的 ServletRequest 的 AsyncListener 类型的侦听器都将在其 onComplete 方法中调用。

the source code of my listener:

我的听众的源代码:

asynCtx.addListener(new AsyncListener()
{
  @Override
  public void onComplete(AsyncEvent asyncEvent) throws IOException
  {
    System.out.println("onComplete(...)");
  }

  @Override
  public void onTimeout(AsyncEvent asyncEvent) throws IOException
  {
    // this will close the request and the context gracefully
    // and the net:ERR is gone.
    asyncEvent.getAsyncContext().complete();
    System.out.println("onTimeout(...)");
  }

  @Override
  public void onError(AsyncEvent asyncEvent) throws IOException
  {
    System.out.println("onError(...)");
  }

  @Override
  public void onStartAsync(AsyncEvent asyncEvent) throws IOException
  {
    System.out.println("onStart(...)");
  }
});

so yes, it was due lack of knowledge. i hope this is helpful for someone.

所以是的,这是由于缺乏知识。我希望这对某人有帮助。

回答by user951335

You can send small "no operation" (noop) chunks to keep the connection alive every 10 seconds or so.

您可以每 10 秒左右发送一次小的“无操作”(noop)块以保持连接处于活动状态。