【问题标题】:WebSocket - Invalid status line javascriptWebSocket - 无效的状态行 javascript
【发布时间】:2016-03-21 17:06:35
【问题描述】:

我在 weblogic 12.1.3 服务器上运行 spring 3.1.2 后端。 为了接受 websocket 连接,我的配置器如下:

public class SpringConfigurator extends Configurator {

    private static final Logger LOGGER = LoggerFactory.make();

    private static final Map<String, Map<Class<?>, String>> cache = new ConcurrentHashMap<String, Map<Class<?>, String>>();

    private static final String MAGIC_STR = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    private static final String NO_VALUE = ObjectUtils.identityToString(new Object());

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {

        WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
        if (wac == null) {
            String message = "Failed to find the root WebApplicationContext. Was ContextLoaderListener not used?";
            LOGGER.error(message);
            throw new IllegalStateException(message);
        }

        String beanName = ClassUtils.getShortNameAsProperty(endpointClass);
        if (wac.containsBean(beanName)) {
            T endpoint = wac.getBean(beanName, endpointClass);
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Using @ServerEndpoint singleton " + endpoint);
            }
            return endpoint;
        }

        Component annot = AnnotationUtils.findAnnotation(endpointClass, Component.class);
        if ((annot != null) && wac.containsBean(annot.value())) {
            T endpoint = wac.getBean(annot.value(), endpointClass);
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Using @ServerEndpoint singleton " + endpoint);
            }
            return endpoint;
        }

        beanName = getBeanNameByType(wac, endpointClass);
        if (beanName != null) {
            return (T) wac.getBean(beanName);
        }

        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Creating new @ServerEndpoint instance of type " + endpointClass);
        }
        return wac.getAutowireCapableBeanFactory().createBean(endpointClass);
    }

    // modifyHandshake() is called before getEndpointInstance()
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        super.modifyHandshake(sec, request, response);

    }

    private String getBeanNameByType(WebApplicationContext wac, Class<?> endpointClass) {

        String wacId = wac.getId();

        Map<Class<?>, String> beanNamesByType = cache.get(wacId);
        if (beanNamesByType == null) {
            beanNamesByType = new ConcurrentHashMap<Class<?>, String>();
            cache.put(wacId, beanNamesByType);
        }

        if (!beanNamesByType.containsKey(endpointClass)) {
            String[] names = wac.getBeanNamesForType(endpointClass);
            if (names.length == 1) {
                beanNamesByType.put(endpointClass, names[0]);
            } else {
                beanNamesByType.put(endpointClass, NO_VALUE);
                if (names.length > 1) {
                    String message = "Found multiple @ServerEndpoint's of type " + endpointClass + ", names=" + names;
                    LOGGER.error(message);
                    throw new IllegalStateException(message);
                }
            }
        }

        String beanName = beanNamesByType.get(endpointClass);
        return NO_VALUE.equals(beanName) ? null : beanName;
    }

}

问题是当我尝试通过 javascript 客户端打开 websocket 连接时,它会在我调试此位置时正确生成响应标头:

@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
    super.modifyHandshake(sec, request, response);
}

但是在客户端它给出了以下错误:

与“ws://localhost:7001/websocket”的 WebSocket 连接失败:>WebSocket 握手期间出错:状态行无效

在 chrome 开发者工具中,响应如下:

HTTP/0.9 200 正常

我认为 http 请求不会升级到 websocket 连接。

非常感谢有关此问题的任何帮助。

【问题讨论】:

  • 我也有同样的问题,但是我使用的是 PHP 棘轮作为服务器,你解决了这个问题吗?
  • 您好,是的,我在我的服务器配置中发现了这一点; 过滤器链接会以某种方式破坏 websocket 握手响应。我实现了一个 websocket 过滤器,将请求直接发送到端点,以绕过过滤器链接request.getRequestDispatcher("/websocket").forward(httpServletRequest, httpServletResponse); 这不是最好的解决方案,但它暂时节省了一天..

标签: javascript spring websocket weblogic12c


【解决方案1】:

我今天在 WebLogic 12.2.1 上测试 http://showcase.omnifaces.org/push/socket 时遇到了这个问题。

webapp 的第一次测试尝试中,WebLogic 在建立 websocket 连接时抛出以下异常:

java.lang.IllegalStateException: The async-support is disabled on this request: weblogic.servlet.internal.ServletRequest
Impl@6682044b[GET /omnifaces.push/counter?e6845a3a-26ed-4520-9824-63ffd85b24eb HTTP/1.1]
    at weblogic.servlet.internal.ServletRequestImpl.startAsync(ServletRequestImpl.java:1949)
    at weblogic.servlet.internal.ServletRequestImpl.startAsync(ServletRequestImpl.java:1925)
    at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:432)
    at weblogic.websocket.tyrus.TyrusServletFilter.doFilter(TyrusServletFilter.java:234)
    ...

事实证明,与我测试过的all other servers相反,WebLogic自己的TyrusServletFilter,它负责处理websocket握手请求,是在通过web.xml提供的过滤器之后内部安装的已部署的 webapp。 webapp 附带一个字符编码过滤器和一个映射到/* 的 GZIP 过滤器,因此它们在 websocket 过滤器之前被调用。乍一看这很奇怪,但我认为它就是这样,所以我只是将 &lt;async-supported&gt;true&lt;/async-supported&gt; 添加到那些 webapp 提供的过滤器中,以便 TyrusServletFilter 可以完成它的工作。

但是,在建立 websocket 连接时,在发送推送消息时客户端发生了 JavaScript 错误,这正是您所面临的:

到 'ws://localhost:7001/omnifaces.push/counter?e6845a3a-26ed-4520-9824-63ffd85b24eb' 的 WebSocket 连接失败:WebSocket 握手期间出错:状态行无效

事实证明,WebSockets 无法处理 GZIP 响应。禁用 GZIP 过滤器后,一切正常。

然而,根本问题是 WebLogic 应该在所有 webapp 提供的过滤器之前安装其TyrusServletFilter。我测试过的所有其他 Java EE 服务器都正确地做到了这一点。如您对问题的评论中所述,您立即将所有 websocket 握手请求发送并转发到其目标 URL 模式的解决方法是一个很好的解决方法。另一种方法是重新配置 web.xml-provided 过滤器以不再匹配 websocket 握手请求,例如通过使用更具体的 URL 模式,或改为映射到特定的 servlet。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-26
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多