赞
踩
Websocket 协议是为了解决 HTTP 协议缺陷而产生的一种通信协议,它能够在客户端和服务器之间建立持久性的连接,并且允许双向通信。
HTTP 协议的请求与响应模式,其实并不适合实时通信的场景。比如聊天室、在线游戏等应用,都需要实时地推送消息到客户端,而 HTTP 协议则需要进行频繁的请求和响应操作,这就会导致网络延迟和更多的带宽消耗。
而 Websocket 则是允许服务器主动向客户端发送消息,而不需要客户端发起请求,从而提高了通信效率和实时性。因此,在微服务架构中,Websocket 技术非常适合作为微服务之间的通信方式。
首先需要在项目中引入 Spring Boot 的 Websocket 模块依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
然后创建一个 Spring Boot 的 Web 应用,并在启动类中添加 @EnableWebSocket 注解。
在服务端,需要定义一个 WebsocketConfig 类,并实现 WebSocketConfigurer 接口。在这个类中,可以自定义 Websocket 消息处理器,并注册到 Websocket 服务中。
@Configuration @EnableWebSocket public class WebsocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*"); } private static class MyWebSocketHandler extends TextWebSocketHandler { private final List<WebSocketSession> sessions = new ArrayList<>(); @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException { for (WebSocketSession s : sessions) { s.sendMessage(message); } } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { sessions.remove(session); } } }
上述代码中,MyWebSocketHandler 是自定义的消息处理器,可以处理客户端发送来的消息,并将消息发送给所有连接的客户端。其中,afterConnectionEstablished() 方法会在客户端和服务器之间建立连接时被调用,afterConnectionClosed() 方法则会在连接关闭时调用。
在客户端,需要构建一个基于 Websocket 的连接,并向服务端发送消息。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Websocket Demo</title> </head> <body> <div id="output"></div> <input type="text" id="input"> <button onclick="sendMessage()">Send</button> <script> const socket = new WebSocket("ws://localhost:8080/ws"); socket.onmessage = function(event) { const output = document.getElementById("output"); const message = event.data; output.innerHTML += "<p>" + message + "</p>"; } function sendMessage() { const input = document.getElementById("input"); const message = input.value; socket.send(message); } </script> </body> </html>
上述代码中,WebSocket() 构造函数中的 ws://localhost:8080/ws 是服务端的 Websocket 地址。在发送消息时,则是调用 socket.send() 方法向服务端发送消息。而在收到服务端的消息时,则会触发 socket.onmessage() 回调函数,并将消息展示在网页中。
本案例采用前后端分离的方式,使用 React 框架构建客户端界面
创建一个 WebSocketConfig 类,并实现 WebSocketConfigurer 接口。在这个类中,注册自定义的 Websocket 消息处理器,并设置允许跨域请求。
@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new ChatWebSocketHandler(), "/chat") .setAllowedOrigins("*") .addInterceptors(new HttpSessionHandshakeInterceptor()); } private static class ChatWebSocketHandler extends TextWebSocketHandler { private final List<WebSocketSession> sessions = new ArrayList<>(); @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException { for (WebSocketSession s : sessions) { if (s != session) { s.sendMessage(message); } } } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { sessions.remove(session); } } }
上述代码中,ChatWebSocketHandler 是自定义的消息处理器,其中 handleTextMessage() 方法实现了用户发送消息到服务端,并将消息发送给所有连接的客户端。而 afterConnectionEstablished() 和 afterConnectionClosed() 方法则分别在建立连接和关闭连接时被调用。
为了保证聊天室的安全性,需要对聊天室进行认证和授权。使用 Spring Security 可以方便地实现这个功能。
首先,需要添加 Spring Security 的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
然后创建一个 SecurityConfig 类,用于配置 Spring Security。
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/chat") .permitAll() .and() .logout() .permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("{noop}password").roles("USER"); } }
上述代码中,configure() 方法用于配置 Spring Security 的认证和授权规则。其中,“/login” 路径不需要认证就可以访问,“/chat” 路径则需要进行认证才能访问。同时,使用 inMemoryAuthentication() 方法可以在内存中定义用户和角色。
在 Controller 中,需要分别对登录和聊天功能进行处理。
@Controller
public class ChatController {
@GetMapping("/login")
public String login() {
return "login";
}
@GetMapping("/chat")
public String chat() {
return "chat";
}
}
客户端使用 React 框架构建,并使用 axios 库进行网络请求。具体代码如下:
import React, { Component } from "react"; import axios from "axios"; class Login extends Component { constructor(props) { super(props); this.state = { username: "", password: "", }; } handleUsernameChange = (event) => { this.setState({ username: event.target.value }); }; handlePasswordChange = (event) => { this.setState({ password: event.target.value }); }; handleSubmit = (event) => { event.preventDefault(); const { username, password } = this.state; axios .post("/login", { username, password }) .then((res) => { this.props.history.push("/chat"); }) .catch((error) => { console.log(error); }); }; render() { return ( <form onSubmit={this.handleSubmit}> <label> Username: <input type="text" value={this.state.username} onChange={this.handleUsernameChange} /> </label> <br /> <label> Password: <input type="password" value={this.state.password} onChange={this.handlePasswordChange} /> </label> <br /> <button type="submit">Submit</button> </form> ); } } export default Login;
import React, { Component } from "react"; import axios from "axios"; class Chat extends Component { constructor(props) { super(props); this.state = { message: "", messages: [], }; } componentDidMount() { const socket = new WebSocket("ws://localhost:8080/chat"); socket.onmessage = (event) => { const message = event.data; this.setState((prevState) => ({ messages: [...prevState.messages, message], })); }; this.socket = socket; } componentWillUnmount() { this.socket.close(); } handleMessageChange = (event) => { this.setState({ message: event.target.value }); }; handleSubmit = (event) => { event.preventDefault(); const message = this.state.message; this.socket.send(message); this.setState({ message: "" }); }; render() { return ( <div> <ul> {this.state.messages.map((message, index) => ( <li key={index}>{message}</li> ))} </ul> <form onSubmit={this.handleSubmit}> <input type="text" value={this.state.message} onChange={this.handleMessageChange} /> <button type="submit">Send</button> </form> </div> ); } } export default Chat;
本文介绍了 Websocket 协议在微服务架构中的应用,并以基于 Websocket 的在线聊天室为例,详细介绍了服务端和客户端的实现方式。通过使用 Spring Boot 和 React 等流行的框架,可以方便地构建高效稳定的基于 Websocket 的微服务应用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。