微服务使用SockJs+Stomp实现Websocket 前后端实例 | Vuex形式断开重连、跨域等等问题踩坑(一)

大家好,我是程序员大猩猩。

之前几篇文章,我们讲了Spring Cloud Gateway的轻量级实现,Nginx的配置概念与实现,如以下往期文章。

轻量级的Spring Cloud Gateway实践,实现api和websocket转发
轻松实现Nginx的HTTP与WebSocket转发:你的网站需要这个!

以上我们提到了SockJs和Stomp,对于Gateway与SockJs的转发连接友好性,那么我们今天就来通过实践来完成这些实例。

首先,我们来了解一下SokeJs和Stomp。

什么是 SockJS

SockJS 是一种浏览器与服务器之间的通信协议,它可以在浏览器和服务器之间建立一个基于 HTTP 的双向通信通道。SockJS 的主要作用是提供一种 WebSocket 的兼容性解决方案,使得不支持 WebSocket 的浏览器也可以使用 WebSocket。

当浏览器不支持 WebSocket 时,SockJS 会自动切换到使用轮询(polling)或长轮询(long-polling)的方式进行通信。

在使用 SockJS 时,首先需要在客户端和服务器端分别引入 sockjs-client.js 和 sockjs-server,然后在客户端通过 new SockJS(url) 的方式建立一个 SockJS 连接。

客户端和服务器端之间的通信是基于事件的,当客户端发送消息时,服务器端会触发一个 onmessage 事件,然后将消息发送回客户端。客户端在接收到消息后,会触发一个 onmessage 事件,然后处理收到的消息。

我们可以在前端代码中使用以下语句来实例化它:

new SockJS('http://*****:8080/ws/user'); // 连接后端接口

什么是 Stomp

STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。

同样,我们怎么初始化使用它:

var url = "ws://*****:8080/ws/user";
var client = Stomp.client(url);
后端实现

当我们工程项目创建好之后,pom内直接引入:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
首先,我们来完成配置类:
@Configuration
// 注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebScoketConfig implements WebSocketMessageBrokerConfigurer {// 输入通道拦截器@Resourceprivate InboundChannelInterceptor inboundChannelInterceptor;// 请求头认证信息使用@Resourceprivate PrincipalHandshakeHandler principalHandshakeHandler;/*** <b>功能描述:</b>注册STOMP协议的节点(endpoint),并映射指定的url<br>*/@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {//注册一个STOMP的endpoint,并指定使用SockJS协议registry.addEndpoint("/ws").setHandshakeHandler(principalHandshakeHandler).setAllowedOriginPatterns("*").withSockJS();}/*** <b>功能描述:</b>配置消息代理(Message Broker)<br>*/@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {//点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理,群发(mass),单独聊天(queue)//推送消息前缀registry.enableSimpleBroker("/topic");//点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/// 应用请求前缀// 推送用户前缀registry.setUserDestinationPrefix("/user");}/*** <b>功能描述:</b>输入通道配置<br>*/@Overridepublic void configureClientInboundChannel(ChannelRegistration registration) {registration.interceptors(this.inboundChannelInterceptor);// 设置拦截器registration.taskExecutor()    // 线程信息.corePoolSize(10)     // 核心线程池.maxPoolSize(20)      // 最多线程池数.keepAliveSeconds(60); // 超过核心线程数后,空闲线程超时60秒则杀死}/*** <b>功能描述:</b>消息传输参数配置<br>*/@Overridepublic void configureWebSocketTransport(WebSocketTransportRegistration registration) {registration.setSendTimeLimit(15 * 1000)    // 超时时间.setSendBufferSizeLimit(512 * 1024) // 缓存空间.setMessageSizeLimit(128 * 1024);   // 消息大小}
}

@EnableWebSocketMessageBroker表示启用Socket代理。

registerStompEndpoints方法内addEndpoint表示接口前缀,当前端连接时,使用http://****:8080/ws方式接入。

setHandshakeHandler添加认证请求头的认证类。

setAllowedOriginPatterns跨域处理

withSockJS是注册SockJS代理

拦截器实现

@Slf4j
@Component
public class InboundChannelInterceptor implements ChannelInterceptor {// 后端实现@Resourceprivate IWebSocketService webSocketServiceImpl;@SneakyThrows@Overridepublic Message<?> preSend(Message<?> message, MessageChannel channel) {StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);if (accessor == null) {log.error("accessor is null");return message;}StompCommand stompCommand = accessor.getCommand();String simpSessionId = accessor.getHeader("simpSessionId").toString();String userId = accessor.getFirstNativeHeader("userId");if (StompCommand.CONNECT.equals(stompCommand)) {this.webSocketServiceImpl.connect(simpSessionId, userId);} else if (StompCommand.DISCONNECT.equals(stompCommand)) {this.webSocketServiceImpl.disconnect(simpSessionId);} else if (StompCommand.SEND.equals(stompCommand)) {this.webSocketServiceImpl.ping(simpSessionId, userId);}return message;}
}

认证信息类

@Slf4j
@Component
public class PrincipalHandshakeHandler extends DefaultHandshakeHandler {/*** <b>功能描述:</b>请求头<br>*/public static final String ACCESS_TOKEN = "token";@Overrideprotected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {/*** 这边可以按需求,如何获取唯一的值,既unicode* 得到的值,会在监听处理连接的属性中,既WebSocketSession.getPrincipal().getName()* 也可以自己实现Principal()*/if (request instanceof ServletServerHttpRequest) {ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;HttpServletRequest httpRequest = servletServerHttpRequest.getServletRequest();/*** 携带参数,你可以cookie,请求头,或者url携带,这边我采用url携带*/String header = httpRequest.getHeader(ACCESS_TOKEN);log.info("token:{}", header);final String token = httpRequest.getParameter(ACCESS_TOKEN);if (StrUtil.isEmpty(token)) {return null;}return () -> token;}return null;}
}

​​​​​​​我们使用Dug模式启动服务看看是否完成,并看看它的Mappings列表。

图片

我们本地输入链接查看,部署成功。

图片

踩坑问题:

1.setAllowedOriginPatterns跨域请求只是一个小点,因为SockJs会封装一个sock-node/info?t=...的接口,我们还必须要全局的设置跨域。

另外网络其他博客,很多会说这个接口404的问题,然后注释掉socket-client什么node_modules js内的1600的行代码。

我是真不信,最后我把我后端代码跨域处理后,就可用了,后端这个接口是默认开放的。有些东西我们真的不要信。

@Component
public class SimpleCORSFilter implements Filter {@Overridepublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) res;response.setHeader("Access-Control-Allow-Credentials", "true");response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD,PUT");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With, token");HttpServletRequest request = (HttpServletRequest) req;if ("OPTIONS".equals(request.getMethod())) {response.setStatus(HttpServletResponse.SC_OK);return;}chain.doFilter(req, res);}@Overridepublic void init(FilterConfig filterConfig) {}@Overridepublic void destroy() {}
}

​​​​​​​

图片

成功,下节我们来看看前端Vue的实现,再见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/907.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot+Vue的Java项目-网上超市系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

平衡二叉树(后序遍历,力扣110)

解题思路&#xff1a;采取后序遍历的好处是先遍历节点得到高度&#xff0c;然后再判断高度差是否大于一&#xff0c;如果是的话就返回-1&#xff0c;不是就返回两高度中较大的高度加一就是父节点的高度 具体代码如下&#xff1a; class Solution { public: int travel(TreeN…

# 从浅入深 学习 SpringCloud 微服务架构(三)注册中心 Eureka(2)

从浅入深 学习 SpringCloud 微服务架构&#xff08;三&#xff09;注册中心 Eureka&#xff08;2&#xff09; 段子手168 1、搭建 EurekaServer 注册中心&#xff0c;使用 Eureka 的步骤&#xff1a; 1&#xff09;搭建 EurekaServer 创建工程&#xff0c;导入依赖坐标&…

论文阅读-Multiple Targets Directed Greybox Fuzzing (Hongliang Liang,2024)

标题: Multiple Targets Directed Greybox Fuzzing (Hongliang Liang,2024) 作者: Hongliang Liang, Xinglin Yu, Xianglin Cheng, Jie Liu, Jin Li 期刊: IEEE Transactions on Dependable and Secure Computing 研究问题: 发现局限性&#xff1a;之前的定向灰盒测试在有…

“中医显示器”是人体健康监测器

随着科技的进步&#xff0c;现代医学设备已经深入到了人们的日常生活中。然而&#xff0c;在这个过程中&#xff0c;我们不应忘记我们的医学根源&#xff0c;中医。我们将中医的望、闻、问、切四诊与现代科技相结合&#xff0c;通过一系列的传感器和算法将人体的生理状态以数字…

部署Hyperledger Fabric测试区块链网络

一. 快速启动区块链测试网络 启动Fabric虚拟机 将 fabric-samples.zip 拷贝进虚拟机 ubzip fabric-samples.zip 解压并重命名为fabric-samples mv fabric-samples-main fabric-samples 拷贝bin和config目录 cd fabric-samples cp ~/fabric/bin bin -r cp ~/fabric/config …

圣地亚哥 Toler 小学利用School AI帮助每个学生都有自己的聊天机器人,提高学习兴趣和效率

圣地亚哥 Toler 小学利用 AI 程序 SchoolAI 平台为学生创建个性化的聊天机器人&#xff0c;帮助他们更好地学习和提问。这个 AI 程序让学生可以在几秒钟内得到问题的答案&#xff0c;激发了他们提出更多问题的好奇心。 管理、调节和指导学生如何通过任务控制使用人工智能。 当…

Linux程序的地址空间,进程终止

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 一.程序的地址空间 1.1程序的地址空间的引入 我们知道frok可以创建…

【SpringBoot实战篇】获取用户详细信息

1 明确需求 1需要获取用户详细信息 2 接口文档 1基本信息 2请求参数 无 3 响应数据 响应数据类型&#xff1a;application/json 响应参数说明&#xff1a; 响应数据样例 3 思路分析 1用户名在请求头里获取 4 开发 4.1 控制器usercontroller GetMapping("/userInfo")p…

实用软件与高效工具汇总(持续更新...)

名人说&#xff1a;莫愁千里路&#xff0c;自有到来风。 ——钱珝 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、软件1、文件搜索类2、截图贴图类3、软件卸载类4、录屏gif类5、护眼调光类6、流程绘图类7、图片…

怎么压缩图片200k以下?压缩图片到指定大小

在工作中&#xff0c;会遇到在某些系统要上传照片&#xff0c;但是对于上传的照片大小有限制&#xff0c;比如限制大小不能超过200KB等&#xff0c;而外业拍摄的照片往往会超过限制的大小&#xff0c;那么这时就需要对照片进行压缩。尤其是我们在面对大量图片需要处理的时候&am…

面试经典150题——跳跃游戏 II

面试经典150题 day10 题目来源我的题解方法一 动态规划方法二 贪心 题目来源 力扣每日一题&#xff1b;题序&#xff1a;45 我的题解 方法一 动态规划 动态规划&#xff0c;当j位置可达i位置时&#xff1a;dp[i]Math.min(dp[i],dp[j]1); 时间复杂度&#xff1a;O( n 2 n^2 n…

mysql按季度统计数据

最近遇到按表里得交付时间换成季度取统计&#xff0c;如下&#xff1a; select sp.Id,sp.title,QUARTER(sp.expected_delivery_time) dateStr,CONCAT(DATE(MIN(sp.expected_delivery_time)),至,DATE(MAX(sp.expected_delivery_time))) dateStr2,sp.DemandType,sp.IndustryGrou…

centos7安装mysql5.7笔记

1 配置yum仓库 1.1更新密钥 #更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 1.2 下载使用wget命令下载MySQL的repo文件 #下载使用wget命令下载MySQL的repo文件 wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 2 使用…

鸿蒙系列--第一个程序HelloWorld

一、下载安装 下载DevEco Studio&#xff08;https://developer.huawei.com/consumer/cn/deveco-studio/&#xff09;并安装 二、创建第一个鸿蒙应用 Next Compile SDK&#xff1a;鸿蒙SDK版本 Mode&#xff1a;ArkTS的声明式开发范式与类Web 开发范式&#xff0c;官方主推S…

二维码如何调整样式?美化二维码生成器的用法

美化二维码功能是一个很常用的二维码编辑功能&#xff0c;一般用来修改二维码颜色、添加logo、更高码点、设置容错率等设置&#xff0c;可以通过简单的步骤将普通的黑白二维码调整成其他的样式。那么美化二维码生成器的使用方法是什么样的呢&#xff1f;下面就让小编来给大家讲…

哈希和布隆过滤器

哈希 布隆过滤器 一致性哈希

Linux-进程间通信:System V消息队列

目录 System V IPC概述标识符与IPC Key System V消息队列创建或打开一个消息队列发送消息接收消息控制消息队列1、IPC_STAT2、IPC_SET3、IPC_RMID 查看系统当前的消息队列代码示例 System V IPC&#xff08;Inter-Process Communication&#xff09;是一组用于在 Unix-like 操作…

3D模型人物换装系统(五 模型核批之后模型uv不正确)模型UV不正确

3D模型人物换装系统&#xff08;五 模型核批之后模型uv不正确&#xff09;模型UV不正确 介绍展示Maya导入查看uvUnity中测试分析没合批为什么没有问题总结 介绍 最近在公司里给公司做模型优化合批的时候发现了模型的uv在合批之后无法正常展示&#xff0c;这里找了很多的原因&a…

牛客网:环形链表的约瑟夫问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;每日一练 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f3dd;1.问题描述&#xff1a; 前言&#xff1a; 约瑟夫问题 有很多种解决办法&#xff0c;下面我们用链表进行解题 题目链…