0

WebSocket サポートのフレームワークとして Atmosphere を使用するチャット サーバーを実行しています。私はatmosphere-jersey maven依存関係を使用しているため、AtmosphereはJerseyを使用しています。

チャット サーバーは Tomcat 7 で実行されており、Tomcat 8 にアップグレードしています。

私たちのクライアントの 1 つは、Tyrus を Java websocket API として使用しています。

チャット サーバーが Tomcat 7 (Java 6、7、または 8) にデプロイされている場合、問題はありません。

Tomcat 8 (Java 8) 上のチャット サーバーでは、Atmosphere を使用するテスト クライアントは正常に動作しますが、Tyrus を使用するクライアントは動作しません。表示されるエラーは次のとおりです。

2017-01-17 02:36:51,114 ERROR () [http-nio-8443-exec-11] ReflectorServletProcessor (?) - onRequest()
java.lang.IllegalArgumentException: Schema specific part is opaque
        at com.sun.jersey.api.uri.UriBuilderImpl.checkSsp(UriBuilderImpl.java:529)
        at com.sun.jersey.api.uri.UriBuilderImpl.replacePath(UriBuilderImpl.java:256)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:703)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at org.atmosphere.util.AtmosphereFilterChain.doFilter(AtmosphereFilterChain.java:135)
        at org.atmosphere.util.AtmosphereFilterChain.invokeFilterChain(AtmosphereFilterChain.java:96)
        at org.atmosphere.handler.ReflectorServletProcessor$FilterChainServletWrapper.service(ReflectorServletProcessor.java:317)
        at org.atmosphere.handler.ReflectorServletProcessor.onRequest(ReflectorServletProcessor.java:160)
        at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:199)
        at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:107)
        at org.atmosphere.container.Servlet30CometSupport.service(Servlet30CometSupport.java:66)
        at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:2078)
        at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:571)
        at org.atmosphere.websocket.DefaultWebSocketProcessor$3.run(DefaultWebSocketProcessor.java:333)
        at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.java:101)
        at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:328)
        at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:525)
        at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:428)
        at org.atmosphere.container.JSR356Endpoint$1.onMessage(JSR356Endpoint.java:213)
        at org.atmosphere.container.JSR356Endpoint$1.onMessage(JSR356Endpoint.java:210)
        at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393)
        at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494)
        at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289)
        at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
        at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
        at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:183)
        at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198)
        at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:669)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)

これは、Tomcat 7 では、Websocket リクエストからのリクエスト URL が「http://localhost:8080/chat/」のように見えるために発生します (リクエストは ws://localhost:8080/chat/ に対して行われますが、変更されています)。 http://どこかに)。しかし、Tomcat 8 では、websocket リクエストからのリクエスト URL は "/chat/" のようになり、スキーマが存在せず、Jersey がエラーをスローします。

これに対処するために、Atmosphere は、Atmosphere クライアントが要求を行うときにスキーマを持つヘッダー「origin」を探します。しかし、Tyrus クライアントがリクエストを行うと、その "origin" ヘッダーに http スキーマが含まれていないため、上記のエラーが発生します。

誰かがこれに対する簡単な解決策のアイデアを持っているか、同様の問題に遭遇したかどうか疑問に思っています. 簡単な解決策をたくさん探しましたが、まだ見つかりません。これがなければ、Atmosphere の使用をやめて、多くのコード リファクタリングを行う別のものを使用する必要があると考えています。

これらは、この問題に対処しているように見えるこの問題に関するチケット/バグへのリンクですが、私は正しいバージョンを持っていますが、まだ問題があります。

https://bz.apache.org/bugzilla/show_bug.cgi?id=56573 https://github.com/Atmosphere/atmosphere/issues/1839

大気バージョン: 2.4.8

ジャージのバージョン (大気経由): 1.19

Tyrus バージョン: 1.13

4

1 に答える 1

0

これを回避するには、フィルタを使用して「origin」ヘッダーを変更し、存在しない場合は http:// スキーマを追加します。この記事は、それを理解するのに役立ちました:サーブレットフィルターでリクエストパラメーターを変更する

import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import javax.servlet.*;

public class FixSchemaFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void destroy() {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            chain.doFilter(new FixSchemaHttpServletRequest((HttpServletRequest) request), response);
        } else {
            chain.doFilter(request, response);
        }
    }

    public class FixSchemaHttpServletRequest extends HttpServletRequestWrapper {

        public FixSchemaHttpServletRequest(HttpServletRequest request) {
            super(request);
        }

        @Override
        public String getHeader(String header) {
            String value = super.getHeader(header);
            if (header.equalsIgnoreCase("origin") && !value.startsWith("http://")) {
                return "http://" + value;
            }
            return value;
        }

        @Override
        public Enumeration getHeaders(String header) {
            Enumeration enumeration = super.getHeaders(header);
            if (header.equalsIgnoreCase("origin") && super.getHeader(header) != null && !super.getHeader(header).startsWith("http://")) {
                return Collections.enumeration(Collections.singleton(getHeader(header)));
            }
            return enumeration;
        }
    }

}

次に、フィルターを web.xml に追加します。

<filter>
        <filter-name>FixSchemaFilter</filter-name>
        <filter-class>com.example.FixSchemaFilter</filter-class>
</filter>
<filter-mapping>
        <filter-name>FixSchemaFilter</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>
于 2017-01-25T15:07:41.270 に答える