Spring WebSocket 404错误的解决方法

 更新时间:2017年12月10日 09:54:11   作者:Silent_Paladin  
这篇文章主要为大家详细介绍了Spring WebSocket 404错误的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

近来学习 Spring WebSocket 时按照 Spring IN ACTION 中示例编写代码,运行时浏览器报404 错误

WebSocket connection to 'ws://localhost/websocket/marco' failed: Error during WebSocket handshake: Unexpected response code: 404

按照 Spring IN ACTION 中步骤:
首先,继承 AbstractWebSocketHandler,重载以下 3 个方法:
- handleTextMessage – 处理文本类型消息
- afterConnectionEstablished – 新连接建立后调用
- afterConnectionClosed – 连接关闭后调用

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

public class MarcoHandler extends AbstractWebSocketHandler {

 protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
  System.out.println("Received message: " + message.getPayload());
  Thread.sleep(2000);
  session.sendMessage(new TextMessage("Polo!"));
 }

 @Override
 public void afterConnectionEstablished(WebSocketSession session) {
  System.out.println("Connection established!");
 }

 @Override
 public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
  System.out.println("Connection closed. Status: " + status);
 }

}

其次,使用 JavaConfig 启用 WebSocket 并映射消息处理器

import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

 @Override
 public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(marcoHandler(), "/marco");
 }

 @Bean
 public MarcoHandler marcoHandler() {
  return new MarcoHandler();
 }

}

最后,编写前端 JS 代码发起连接请求及后续消息交互

var url = 'ws://' + window.location.host + '/websocket/marco';
var sock = new WebSocket(url);

sock.onopen = function() {
 console.log('Opening');
 sock.send('Marco!');
};

sock.onmessage = function(e) {
 console.log('Received Message: ', e.data);
 setTimeout(function() {
  sayMarco()
 }, 2000);
};

sock.onclose = function() {
 console.log('Closing');
};

function sayMarco() {
 console.log('Sending Marco!');
 sock.send('Marco!');
}

部署后打开浏览器运行,直接报 404 错误

上网搜索了一晚上解决方案,包括参考 stackoverflow.com 上的经验都未解决该问题,直到查看到以下文章:
Spring集成webSocket页面访问404问题的解决方法

在此自己也做个记录避免以后遗忘。

WebSocket 实质上借用 HTTP 请求进行握手,启用 Spring WebSocket 需要在 org.springframework.web.servlet.DispatcherServlet 里配置拦截此请求

以下是解决步骤:

首先,修改 WebSocketConfig 类定义,在类上添加 @Configuration 注解,表明该类以 JavaConfig 形式用作 bean 定义的源(相当于 XML 配置中的 <beans> 元素)。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

 @Override
 public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  registry.addHandler(marcoHandler(), "/marco");
 }

 @Bean
 public MarcoHandler marcoHandler() {
  return new MarcoHandler();
 }

}

其次,使用 JavaConfig 配置 DispatcherServlet,继承org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer ,重载以下 3 个方法:
- getRootConfigClasses – 返回带有 @Configuration 注解的类将会用来配置 ContextLoaderListener 创建的应用上下文中的 bean
- getServletConfigClasses – 返回带有 @Configuration 注解的类将会用来定义 DispatcherServlet 应用上下文中的 bean
- getServletMappings – 将一个或多个路径映射到 DispatcherServlet 上

实际上,如果只需要 Spring WebSocket 生效,则只需要在 getServletConfigClasses 方法中返回用来定义 DispatcherServlet 应用上下文中的 bean

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebSocketInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

 @Override
 protected Class<?>[] getRootConfigClasses() {
  return null;
 }

 @Override
 protected Class<?>[] getServletConfigClasses() {
  return new Class<?>[] {WebSocketConfig.class};
 }

 @Override
 protected String[] getServletMappings() {
  return new String[] {"/"};
 }

}

重新部署后代开浏览器运行成功

客户端消息

服务器消息

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java微信公众平台开发(1) 接入微信公众平台

    Java微信公众平台开发(1) 接入微信公众平台

    这篇文章主要为大家详细介绍了Java微信公众平台开发第一步,接入微信公众平台,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • java实现同步回调的示例代码

    java实现同步回调的示例代码

    同步回调是一种在调用代码中同步执行回调函数的编程模式,在Java中,通过定义和实现接口来构建同步回调,本文就来介绍一下如何实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-09-09
  • java随机生成8位数授权码的实例

    java随机生成8位数授权码的实例

    下面小编就为大家带来一篇java随机生成8位数授权码的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • Java 进制转换的方法

    Java 进制转换的方法

    这篇文章介绍了Java 进制转换的方法,有需要的朋友可以参考一下
    2013-09-09
  • Spring与MyBatis集成 AOP整合PageHelper插件的操作过程

    Spring与MyBatis集成 AOP整合PageHelper插件的操作过程

    Spring与MyBatis集成的主要目的是为了提供更强大的数据访问和事务管理能力,以及简化配置和提高开发效率,这篇文章主要介绍了Spring与MyBatis集成AOP整合PageHelper插件,需要的朋友可以参考下
    2023-08-08
  • idea中打开项目时import project和open区别详解

    idea中打开项目时import project和open区别详解

    本文主要介绍了idea中打开项目时import project和open区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Rabbitmq中的channel接口常用方法详解

    Rabbitmq中的channel接口常用方法详解

    这篇文章主要介绍了Rabbitmq中的channel接口常用方法详解,为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将该消息删除,需要的朋友可以参考下
    2023-09-09
  • IDEA插件之快速删除Java代码中的注释

    IDEA插件之快速删除Java代码中的注释

    这篇文章主要介绍了IDEA插件之快速删除Java代码中的注释,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • 详解spring cloud分布式整合zipkin的链路跟踪

    详解spring cloud分布式整合zipkin的链路跟踪

    这篇文章主要介绍了详解spring cloud分布式整合zipkin的链路跟踪,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • java中ThreadLocal的基本原理

    java中ThreadLocal的基本原理

    本文讲解了java中ThreadLocal的一些基本原理,文中关于ThreadLocal的原理讲解的非常详细,感兴趣的朋友一起看看吧
    2021-08-08

最新评论