当使用HTML5服务器事件和Java Servlets时如何防止net::ERR_INCOMPLETE_CHUNKED_ENCODING错误?

12

我刚开始尝试使用服务器事件,但是遇到了一个谷歌错误信息,我希望能够理解。我很快在网上搜索了一下,但没有找到解释,所以我想可能是我做错了什么。

在服务器端,我有一个简单的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();
    }
  });

}

在客户端我只需:

$(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...")
});

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

GET [HttpOfLocalhost]/events net::ERR_INCOMPLETE_CHUNKED_ENCODING

为什么会出现这种情况呢?

然后请求会被中止,并立即开始一个新的请求,以便不会导致应用程序崩溃,但是在控制台上看到错误消息很不好。

我的开发者控制台截图:

enter image description here

请求/响应详情:

enter image description here

时间记录表明,这总是发生在30秒后:

enter image description here

谢谢!

2个回答

6

好的,我无法静止不动地观察发生了什么。

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

我使用以下内容进行了检查:

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

显示了:

Current Timeout is: 30000 ms

为了避免出现net:ERR消息,有人可以将超时时间设置为0。但是这样事件线程会永远运行下去(不幸的是)。 另一个解决方案是,添加AsyncListenerAsyncContext中,并在onTimeout()方法中调用complete()方法。 从complete()方法的API文档中可以看到: 完成在初始化此AsyncContext的请求上启动的异步操作,关闭用于初始化此AsyncContext的响应。任何已注册到为创建此AsyncContext的ServletRequest的类型为AsyncListener的侦听器都将在其onComplete方法中被调用。

我的监听器源代码:

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(...)");
  }
});

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


2
请告诉我。我遇到了这个错误,但我没有使用异步操作。当我访问页面时,出现了这个错误。 - Tsyklop

3

您可以每隔10秒钟发送小的“无操作”(noop)块以保持连接活动状态。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接