tomcat - Tomcat 8 和非 Atmosphere 客户端的 Atmosphere+Jersey 错误

标签 tomcat websocket tomcat8 atmosphere tyrus

我运行一个聊天服务器,它使用 Atmosphere 作为支持 websocket 的框架。 Atmosphere 使用 Jersey,因为我使用 atmosphere-jersey maven 依赖项。

聊天服务器在 Tomcat 7 上运行,我们正在升级到 Tomcat 8。

我们的一个客户使用 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 客户端发出请求时查找具有模式的 header “origin”。但是,当 Tyrus 客户端发出请求时,该“来源” header 不包含导致上述错误的 http 架构。

我想知道是否有人对此有任何简单的解决方案或遇到过类似问题。我已经做了很多搜索来寻找一个简单的解决方案,但还没有找到。如果没有,我们将不得不停止使用 Atmosphere 并使用其他需要进行大量代码重构的东西。

这些是关于此问题的票据/错误的一些链接,这些链接似乎已经解决了这个问题,但我有正确的版本,但仍然有问题。

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

Atmosphere 版本:2.4.8

Jersey 版本(通过 Atmosphere 层):1.19

泰鲁斯版本:1.13

最佳答案

解决方法是通过过滤器更改“来源” header ,如果不存在则添加 http://架构。这篇文章帮助解决了这个问题:Modify request parameter with servlet filter

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>

关于tomcat - Tomcat 8 和非 Atmosphere 客户端的 Atmosphere+Jersey 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41769097/

相关文章:

java - Spring MVC : Tomcat 404 The requested resource is not available

java - UnsupportedClassVersionError : Bad version number in . 类文件

python - 如何使用 Python 的内置日志记录和 Asyncio(权限错误)

macos - 如何在 Mac OS X 中连接 NetBeans 8 和 Tomcat 8?

tomcat - 如何在 Elastic Beanstalk 上使用 Tomcat 8 设置 Loggly

scala - 如何在 Tomcat 上部署 Scala/akka 应用程序?

java - spring hibernate对内存消耗的影响比纯jsp/servlet多少?

http - 为什么 websocket 协议(protocol)的设计者不使用 WS 而不是 GET 作为方法?

python - 为什么我收到 "WebSocket connection is closed: code = 1000 (OK), no reason"

java - JAVA(tomcat)中的环境变量