嵌入式 Tomcat 给出“不允许 HTTP 升级到 WebSocket”错误

Posted

技术标签:

【中文标题】嵌入式 Tomcat 给出“不允许 HTTP 升级到 WebSocket”错误【英文标题】:Embedded Tomcat gives "did not permit the HTTP upgrade to WebSocket" error 【发布时间】:2018-11-25 05:23:22 【问题描述】:

我一直在尝试开发一个带有 @WebServlet(用于提供网页和 RESTful 请求)和 @ServerEndpoint(websocket)的嵌入式 Tomcat 的 webapp。到目前为止,它在我的 Intellij 上运行良好。但是,当我使用 Maven 构建代码并改为执行 jar 文件时。我总是收到以下错误:

原因:javax.websocket.DeploymentException:来自服务器的 HTTP 响应 [HTTP/1.1 404 Not Found] 不允许 HTTP 升级到 WebSocket

错误追溯到我的套接字客户端,我试图打开一个连接:

container.connectToServer(this, endpointURI);

供您参考,客户端的外观如下:

@ClientEndpoint
public class SocketClient 

    Session userSession = null;
    private MessageHandler messageHandler;

    public SocketClient(URI endpointURI) 
        try 
            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
            container.connectToServer(this, endpointURI);
         catch (Exception e) 
            throw new RuntimeException(e);
        
    

    @OnOpen
    public void onOpen(Session userSession) 
        System.out.println("opening websocket");
        this.userSession = userSession;
    

    @OnClose
    public void onClose(Session userSession, CloseReason reason) 
        System.out.println("closing websocket");
        this.userSession = null;
    

    @OnMessage
    public void onMessage(String message) 
        if (this.messageHandler != null) 
            this.messageHandler.handleMessage(message);
        
    

    public void addMessageHandler(MessageHandler msgHandler) 
        this.messageHandler = msgHandler;
    

    public void sendMessage(String message) 
        this.userSession.getAsyncRemote().sendText(message);
    

    public static interface MessageHandler 
        public void handleMessage(String message);
    

而我的 websocket 端点定义如下:

@ServerEndpoint(
    value="/hi",
    decoders = MessageDecoder.class,
    encoders = MessageEncoder.class )
public class SocketEndpoint 

    private Session session;

    private static Set<SocketEndpoint> chatEndpoints
            = new CopyOnWriteArraySet<>();

    public SocketEndpoint() 
        System.out.println("class loaded " + this.getClass());
    

    @OnOpen
    public void onOpen(Session session) 
        this.session = session;
        chatEndpoints.add(this);
        System.out.println(session.getId() + " has open a connection");
        try 
            session.getBasicRemote().sendText("Connection Established");
         catch (IOException ex) 
            ex.printStackTrace();
        
    

    @OnMessage
    public void onMessage(Message message, Session session)  /* ... */

    @OnClose
    public void onClose(Session session)  /* ... */

    @OnError
    public void onError(Session session, Throwable throwable)  /* ... */     

就像我说的,当我在 Intellij 上运行代码时它运行良好,但有趣的是,当我将鼠标悬停在 SocketEndpoint 上时,我会得到一个工具提示,说这个类从未使用过,而其他 HttpServlet 类他们没有使用t有这样的问题。我还通过检查 SocketEndpoint 类是否已加载(查看构造函数)来验证,当我执行 jar 时它没有加载。

以及任何需要的依赖项(可能)我已经添加了它们(pom.xml):

<properties>
    <tomcat.version>8.0.28</tomcat.version>
    <gson.version>2.8.0</gson.version>
    <junit.jupiter.version>5.2.0</junit.jupiter.version>
    <junit.platform.version>1.2.0</junit.platform.version>
    <junit.vintage.version>5.2.0</junit.vintage.version>
    <log4j2.version>2.8.2</log4j2.version>
    <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-logging-juli</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jasper</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jasper-el</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jsp-api</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-websocket</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jasper-el</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jsp-api</artifactId>
        <version>$tomcat.version</version>
    </dependency>
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-engine</artifactId>
        <version>$junit.platform.version</version>
    </dependency>
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-runner</artifactId>
        <version>$junit.platform.version</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>$junit.vintage.version</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-migrationsupport</artifactId>
        <version>$junit.vintage.version</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-api</artifactId>
        <version>1.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-client-api</artifactId>
        <version>1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>$log4j2.version</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple -->
    <dependency>
        <groupId>com.googlecode.json-simple</groupId>
        <artifactId>json-simple</artifactId>
        <version>1.1</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>$gson.version</version>
    </dependency>
</dependencies>

任何帮助将不胜感激。我看到大多数遇到类似问题的人都在使用 Spring,而我没有。

【问题讨论】:

【参考方案1】:

错误显示为您的客户端尝试连接到未找到的 Web 套接字 (URL)。

Caused by: javax.websocket.DeploymentException: The HTTP response from the server [HTTP/1.1 404 Not Found] did not permit the HTTP upgrade to WebSocket

确保您在应用程序中提及任何上下文路径或找到确切的 websocket URL。

【讨论】:

以上是关于嵌入式 Tomcat 给出“不允许 HTTP 升级到 WebSocket”错误的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot - 当我调用 API 时,它给出 404 错误

微服务:嵌入式 tomcat 与独立 tomcat:差异

Tomcat专题-----Tomcat源码嵌入式Tomcat

用于嵌入式 Tomcat 8.5 的 Tomcat Maven 插件

Spring Boot 嵌入式 Tomcat 性能

使用embeded tomcat进行嵌入式javaee开发-启动tomcat