web-dev-qa-db-ja.com

HTML5サーバーイベントとJavaサーブレットを使用しているときにnet :: ERR_INCOMPLETE_CHUNKED_ENCODINGを防ぐ方法は?

サーバーイベントで遊んだところ、chromeエラーメッセージが表示されます。理解したいと思います。ウェブをすぐに検索しましたが、説明が見つからなかったので、ひどく悪いことをしてください。

サーバー側には、リクエストを受け入れてダミーのイベント作成タスクを作成する単純なサーブレットがあります。

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ファイルをロードすると正常に動作し、イベントが受信されてコンソールに書き込まれます。しかし秒後エラーメッセージが表示されます。

GET [HttpOfLocalhost]/events net :: ERR_INCOMPLETE_CHUNKED_ENCODING

どうして?

リクエストが強制終了され、新しいリクエストがすぐに開始されるため、アプリケーションは強制終了されませんが、コンソールのエラーメッセージは適切ではありません。

私の開発者コンソールのスクリーンショット:

enter image description here

リクエスト/応答の詳細:

enter image description here

タイミング、これはそれが常に30秒後に発生することを示しています:

enter image description here

ありがとう!

11
Chris

わかりました、それで私はじっと立って、何が起こっているのかよく見ることができませんでした。

AsyncContext オブジェクトには setTimeout(...) メソッドがあります。私のバージョンのTomcat(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 に追加し、 completeを呼び出すことです() メソッドは onTimeout() メソッド内にあります。

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

そうはい、それは知識の欠如によるものでした。これが誰かに役立つことを願っています。

6
Chris

小さな「操作なし」(noop)チャンクを送信して、10秒程度ごとに接続を維持することができます。

3
user951335