皆さん!
WebSocket を使用してチャット Web アプリケーションを実装していますが、Jetty 9.1.3.v20140225 で実行すると、接続が確立された直後に、サーバー側から送信された一部のメッセージがクライアント側で受信されません。不思議なことに、この誤動作は一部のメッセージで発生しますが、他のメッセージは問題ありません (最後に私の PS を参照してください)。
Chrome 33 ( permessage-deflate 拡張機能を使用していることはわかっています) と FireFox 28 (使用していない) の両方を試しましたが、同様の結果が得られました。実際、Chrome はいくつかのメッセージを受信しますが、FireFox は何も受信しません。
アプリケーションがTomCat 7.0.47で実行されている場合、問題なく動作するため、問題はJettyにあると思われます...
問題を再現する最小限のアプリケーションのコードを見てみましょう。
最初に、対応するボタンをクリックして、接続、メッセージの送信 (および応答の受信)、および WebSocket の切断を行うことができる簡単なページがあります。
こんにちは.html:
<html>
<head>
<meta charset="ISO-8859-1">
<title>Minimum - WebSocket Sandbox</title>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#connect").click(function() {
connect();
});
$("#send").click(function() {
send("John Doe");
});
$("#disconnect").click(function() {
disconnect();
});
});
</script>
<script>
var wsocket;
function connect() {
var base = getAppLocation("ws:");
wsocket = new WebSocket(base + "/hello");
wsocket.onmessage = function(e) {
log("<<< " + e.data);
};
wsocket.onopen = function() {
log("Connection opened.");
};
wsocket.onclose = function(e) {
log("Connection closed. Reason: (" + e.code + ") " + e.reason);
};
wsocket.onerror = function(e) {
log("Error!");
};
}
function disconnect() {
wsocket.close(1000, "Closed by user.");
wsocket = null;
}
function send(msg) {
if ( !wsocket || wsocket.readyState != WebSocket.OPEN ) {
log("Not connected.");
return;
}
wsocket.send(msg);
log(">>> " + msg);
}
function log(msg) {
$("#output").append(msg + "<br/>");
}
/**
* This just ajust WebSocket URL ocording to the server serving the page.
*/
function getAppLocation(proto) {
if ( !proto ) {
proto = window.location.protocol;
}
else if ( proto == "ws:" && window.location.protocol == "https:" ) {
proto = "wss:";
}
var host = window.location.host;
var path = window.location.pathname.split('/')[1];
var base = proto + "//" + host + "/" + path;
return base;
}
</script>
</head>
<body>
<div>
<button id="connect">Connect</button>
<button id="send">Send</button>
<button id="disconnect">Disconnect</button>
</div>
<div id="output"></div>
</body>
</html>
サーバー側には、接続が開かれるとすぐにクライアントにメッセージを送信する単一のエンドポイントがあります (コメントアウトされた行は、Chrome クライアントによって受信されるサンプル メッセージを示しています)。また、クライアントから受信したメッセージをエコーします。
ハローエンドポイント:
package com.ciandt.helenov.sandbox.websocket.min;
import java.io.IOException;
import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/hello")
public class HelloEndpoint {
@OnOpen
public void onOpen ( Session session, EndpointConfig conf ) {
try {
// this is not received in the client
session.getBasicRemote().sendText( "o" );
// this is (but only if client is a Chrome)
// session.getBasicRemote().sendText( "a[\"100\"]" );
}
catch ( IOException e ) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage ( Session session, String msg ) {
try {
session.getBasicRemote().sendText( "Hello, " + msg + "!" );
}
catch ( IOException e ) {
e.printStackTrace();
}
}
}
最後に、Web アプリケーションをパッケージ化して実行する pom.xml があります。Eclipse内に埋め込まれたmavenプラグインを介して、Jetty(問題が発生する場所)とTomCat(問題なく動作する)の両方を実行しています
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>WebSocket Mininum</name>
<description>WebSocket Minimum Web Application</description>
<groupId>com.ciandt.helenov.sandbox</groupId>
<artifactId>ws-min</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<slf4j.version>1.7.2</slf4j.version>
<logback.version>1.0.13</logback.version>
<jetty.version>9.1.3.v20140225</jetty.version>
<tomcat.version>7.0.47</tomcat.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerVersion>${java.version}</compilerVersion>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
<!-- Support to use Eclipse -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.7</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<wtpversion>2.0</wtpversion>
</configuration>
</plugin>
<!-- Support to run Jetty on Eclipse -->
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<webAppConfig>
<contextPath>/${project.artifactId}</contextPath>
</webAppConfig>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>9090</port>
<path>/${project.artifactId}</path>
<systemProperties>
<appserver.base>${project.build.directory}/tomcat-base</appserver.base>
<appserver.home>${project.build.directory}/tomcat-home</appserver.home>
<derby.system.home>${project.build.directory}/tomcat-base/logs</derby.system.home>
<java.io.tmpdir>${project.build.directory}</java.io.tmpdir>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
それで全部です!
(mvn jetty:run を呼び出して) Jetty でアプリケーションを実行しているときに、(ページの [接続] ボタンをクリックして) WebSocket に接続するように要求すると、エンドポイントの onOpen() メソッドが実行され、メッセージがクライアントに送り返されますが、表示されると思っていたので受け取っていません。(mvn tomcat7:run を呼び出して) TomCat で同じアプリケーションを実行すると、非常にうまく機能します。
誰かが同様の問題を抱えていましたか?誰が何が起こっているのか手がかりを持っていますか? Jetty サーバーのバグでしょうか?
TIAとよろしく!
ヘレノ
PS:アプリケーションでSpringとSockJSを使用するつもりですが、接続が開かれた直後にSockJSがサーバー上で「オープンフレーム」(「o」のみ)を送信しますが、受信されないため、WebSocketをあきらめてフォールバックに進みます接続し、XHR ストリーミングを行います。それは私が避けようとしているものです。しかし、Spring と SockJS の両方を使用せずに問題を再現できたので (提示されたコードに示されているように)、問題への関与から解放しました。