最近有个需求是后端主动推送消息给前端,通过一番艰难险阻总算是给完成了,选择使用的是websocket,可以前后端进行通信
1、框架:
后端:springboot2.x
前端:vue2.x
2、原理:
后端建立一个websocket服务器,提供一个url,前端通过url与后端websocket服务器进行连接
3、使用的依赖:
在WebSocketConfig中会用到
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
4、websocket配置:
WebSocketConfig
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
5、建立webSocket服务器:
WebSocket
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/webSocket/{username}")
@Slf4j
@Component
public class WebSocket {
private static int onlineCount = 0;
private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();
private Session session;
private String username;
@OnOpen
public void onOpen(@PathParam("username") String username, Session session) {
this.username = username;
this.session = session;
WebSocket.onlineCount++;
clients.put(username, this);
}
@OnClose
public void onClose() {
clients.remove(username);
WebSocket.onlineCount--;
}
@OnMessage
public void onMessage(String message) {}
@OnError
public void onError(Session session, Throwable throwable) {
log.error("WebSocket发生错误:" + throwable.getMessage());
}
public static void sendMessage(String message) {
// 向所有连接websocket的客户端发送消息
// 可以修改为对某个客户端发消息
for (WebSocket item : clients.values()) {
item.session.getAsyncRemote().sendText(message);
}
}
}
6、前端代码:
在需要建立连接的地方调用这个方法即可
// 与websocket服务器创建连接
createWebSocket() {
// 注意这里的端口号是后端服务的端口号,后面的是后端正常请求的路径,ziyuan是我的项目名,最后面的是我放在cookie中的当前登陆用户
let websocket = new WebSocket('ws://127.0.0.1:9000/ziyuan/webSocket/' + this.$cookie.get('nameOrEmail'))
// 连接成功时
websocket.onopen = () => {
// websocket.send('hello')
}
websocket.onmessage = event => {
// 后端发送的消息在event.data中
console.log(event.data)
}
websocket.onclose = function () {
console.log('关闭了')
}
// 路由跳转时结束websocket链接
this.$router.afterEach(function () {
websocket.close()
})
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常
window.onbeforeunload = function () {
websocket.close()
}
}
7、使用webSocket:
这是我在文件时上传线程执行完毕后,通知前端是否上传成功
遇到的问题:
1、Error during WebSocket handshake: Unexpected response code: 200
原因:建立请求被项目中拦截器给拦截了
解决:在拦截器中放行webSocket的连接路径
这是我的shiro拦截器配置
2、Error during WebSocket handshake: Unexpected response code: 404
原因:在前端请求的路径不是完整的,我没有加上项目的路径
解决:保证前端请求的路径是正确的
我漏了这个
3、webSocket连接失败,WebSocket is closed before the connection is established
原因:不清楚,当时还没有加上webSocketConfig配置类,而且拦截器也没有对路径放行
解决:按照上面走就没错
lbwnb!!!
借鉴:
Websocket实现Java后台主动推送消息到前台
Vue+Springboot前后端分离websocket的使用
WebSocket连接问题