サーバーイベントで遊んだところ、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
どうして?
リクエストが強制終了され、新しいリクエストがすぐに開始されるため、アプリケーションは強制終了されませんが、コンソールのエラーメッセージは適切ではありません。
私の開発者コンソールのスクリーンショット:
リクエスト/応答の詳細:
タイミング、これはそれが常に30秒後に発生することを示しています:
ありがとう!
わかりました、それで私はじっと立って、何が起こっているのかよく見ることができませんでした。
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に設定する可能性があります。しかし、イベントスレッドは(残念ながら)永久に実行し続けます。私が使用した別の解決策は、 AsyncListener を AsyncContext に追加し、 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(...)");
}
});
そうはい、それは知識の欠如によるものでした。これが誰かに役立つことを願っています。
小さな「操作なし」(noop)チャンクを送信して、10秒程度ごとに接続を維持することができます。