从零开始,手把手教你实现基于 Websocket 的微服务
文章目录
从零开始,手把手教你实现基于 Websocket 的微服务
1. Websocket 简介
Websocket 协议是为了解决 HTTP 协议缺陷而产生的一种通信协议,它能够在客户端和服务器之间建立持久性的连接,并且允许双向通信。
HTTP 协议的请求与响应模式,其实并不适合实时通信的场景。比如聊天室、在线游戏等应用,都需要实时地推送消息到客户端,而 HTTP 协议则需要进行频繁的请求和响应操作,这就会导致网络延迟和更多的带宽消耗。
而 Websocket 则是允许服务器主动向客户端发送消息,而不需要客户端发起请求,从而提高了通信效率和实时性。因此,在微服务架构中,Websocket 技术非常适合作为微服务之间的通信方式。
2. 构建基于 Websocket 的微服务应用
2.1 准备工作
首先需要在项目中引入 Spring Boot 的 Websocket 模块依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
然后创建一个 Spring Boot 的 Web 应用,并在启动类中添加 @EnableWebSocket 注解。
2.2 编写服务端代码
在服务端,需要定义一个 WebsocketConfig 类,并实现 WebSocketConfigurer 接口。在这个类中,可以自定义 Websocket 消息处理器,并注册到 Websocket 服务中。
@Configuration
@EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*");}private static class MyWebSocketHandler extends TextWebSocketHandler {private final List<WebSocketSession> sessions = new ArrayList<>();@Overridepublic void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {for (WebSocketSession s : sessions) {s.sendMessage(message);}}@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {sessions.add(session);}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessions.remove(session);}}
}
上述代码中,MyWebSocketHandler 是自定义的消息处理器,可以处理客户端发送来的消息,并将消息发送给所有连接的客户端。其中,afterConnectionEstablished() 方法会在客户端和服务器之间建立连接时被调用,afterConnectionClosed() 方法则会在连接关闭时调用。
2.3 编写客户端代码
在客户端,需要构建一个基于 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() 回调函数,并将消息展示在网页中。
3. 技术实践案例:基于 Websocket 的在线聊天室
3.1 界面设计
本案例采用前后端分离的方式,使用 React 框架构建客户端界面
3.2 服务端实现
3.2.1 WebSocket 配置
创建一个 WebSocketConfig 类,并实现 WebSocketConfigurer 接口。在这个类中,注册自定义的 Websocket 消息处理器,并设置允许跨域请求。
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic 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<>();@Overridepublic void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {for (WebSocketSession s : sessions) {if (s != session) {s.sendMessage(message);}}}@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {sessions.add(session);}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessions.remove(session);}}
}
上述代码中,ChatWebSocketHandler 是自定义的消息处理器,其中 handleTextMessage() 方法实现了用户发送消息到服务端,并将消息发送给所有连接的客户端。而 afterConnectionEstablished() 和 afterConnectionClosed() 方法则分别在建立连接和关闭连接时被调用。
3.2.2 Spring Security 配置
为了保证聊天室的安全性,需要对聊天室进行认证和授权。使用 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 {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").defaultSuccessUrl("/chat").permitAll().and().logout().permitAll();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password("{noop}password").roles("USER");}
}
上述代码中,configure() 方法用于配置 Spring Security 的认证和授权规则。其中,“/login” 路径不需要认证就可以访问,“/chat” 路径则需要进行认证才能访问。同时,使用 inMemoryAuthentication() 方法可以在内存中定义用户和角色。
3.2.3 Controller 实现
在 Controller 中,需要分别对登录和聊天功能进行处理。
@Controller
public class ChatController {@GetMapping("/login")public String login() {return "login";}@GetMapping("/chat")public String chat() {return "chat";}
}
3.3 客户端实现
客户端使用 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:<inputtype="text"value={this.state.username}onChange={this.handleUsernameChange}/></label><br /><label>Password:<inputtype="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}><inputtype="text"value={this.state.message}onChange={this.handleMessageChange}/><button type="submit">Send</button></form></div>);}
}export default Chat;
4. 总结
本文介绍了 Websocket 协议在微服务架构中的应用,并以基于 Websocket 的在线聊天室为例,详细介绍了服务端和客户端的实现方式。通过使用 Spring Boot 和 React 等流行的框架,可以方便地构建高效稳定的基于 Websocket 的微服务应用。