從零開(kāi)始,手把手教你實(shí)現(xiàn)基于 Websocket 的微服務(wù)
1. Websocket 簡(jiǎn)介
Websocket 協(xié)議是為了解決 HTTP 協(xié)議缺陷而產(chǎn)生的一種通信協(xié)議,它能夠在客戶端和服務(wù)器之間建立持久性的連接,并且允許雙向通信。
HTTP 協(xié)議的請(qǐng)求與響應(yīng)模式,其實(shí)并不適合實(shí)時(shí)通信的場(chǎng)景。比如聊天室、在線游戲等應(yīng)用,都需要實(shí)時(shí)地推送消息到客戶端,而 HTTP 協(xié)議則需要進(jìn)行頻繁的請(qǐng)求和響應(yīng)操作,這就會(huì)導(dǎo)致網(wǎng)絡(luò)延遲和更多的帶寬消耗。
而 Websocket 則是允許服務(wù)器主動(dòng)向客戶端發(fā)送消息,而不需要客戶端發(fā)起請(qǐng)求,從而提高了通信效率和實(shí)時(shí)性。因此,在微服務(wù)架構(gòu)中,Websocket 技術(shù)非常適合作為微服務(wù)之間的通信方式。
2. 構(gòu)建基于 Websocket 的微服務(wù)應(yīng)用
2.1 準(zhǔn)備工作
首先需要在項(xiàng)目中引入 Spring Boot 的 Websocket 模塊依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
然后創(chuàng)建一個(gè) Spring Boot 的 Web 應(yīng)用,并在啟動(dòng)類中添加 @EnableWebSocket 注解。
2.2 編寫(xiě)服務(wù)端代碼
在服務(wù)端,需要定義一個(gè) WebsocketConfig 類,并實(shí)現(xiàn) WebSocketConfigurer 接口。在這個(gè)類中,可以自定義 Websocket 消息處理器,并注冊(cè)到 Websocket 服務(wù)中。
@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 是自定義的消息處理器,可以處理客戶端發(fā)送來(lái)的消息,并將消息發(fā)送給所有連接的客戶端。其中,afterConnectionEstablished() 方法會(huì)在客戶端和服務(wù)器之間建立連接時(shí)被調(diào)用,afterConnectionClosed() 方法則會(huì)在連接關(guān)閉時(shí)調(diào)用。
2.3 編寫(xiě)客戶端代碼
在客戶端,需要構(gòu)建一個(gè)基于 Websocket 的連接,并向服務(wù)端發(fā)送消息。
<!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() 構(gòu)造函數(shù)中的 ws://localhost:8080/ws 是服務(wù)端的 Websocket 地址。在發(fā)送消息時(shí),則是調(diào)用 socket.send() 方法向服務(wù)端發(fā)送消息。而在收到服務(wù)端的消息時(shí),則會(huì)觸發(fā) socket.onmessage() 回調(diào)函數(shù),并將消息展示在網(wǎng)頁(yè)中。
3. 技術(shù)實(shí)踐案例:基于 Websocket 的在線聊天室
3.1 界面設(shè)計(jì)
本案例采用前后端分離的方式,使用 React 框架構(gòu)建客戶端界面
3.2 服務(wù)端實(shí)現(xiàn)
3.2.1 WebSocket 配置
創(chuàng)建一個(gè) WebSocketConfig 類,并實(shí)現(xiàn) WebSocketConfigurer 接口。在這個(gè)類中,注冊(cè)自定義的 Websocket 消息處理器,并設(shè)置允許跨域請(qǐng)求。
@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() 方法實(shí)現(xiàn)了用戶發(fā)送消息到服務(wù)端,并將消息發(fā)送給所有連接的客戶端。而 afterConnectionEstablished() 和 afterConnectionClosed() 方法則分別在建立連接和關(guān)閉連接時(shí)被調(diào)用。
3.2.2 Spring Security 配置
為了保證聊天室的安全性,需要對(duì)聊天室進(jìn)行認(rèn)證和授權(quán)。使用 Spring Security 可以方便地實(shí)現(xiàn)這個(gè)功能。
首先,需要添加 Spring Security 的依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
然后創(chuàng)建一個(gè) 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 的認(rèn)證和授權(quán)規(guī)則。其中,“/login” 路徑不需要認(rèn)證就可以訪問(wèn),“/chat” 路徑則需要進(jìn)行認(rèn)證才能訪問(wèn)。同時(shí),使用 inMemoryAuthentication() 方法可以在內(nèi)存中定義用戶和角色。
3.2.3 Controller 實(shí)現(xiàn)
在 Controller 中,需要分別對(duì)登錄和聊天功能進(jìn)行處理。
@Controller
public class ChatController {
@GetMapping("/login")
public String login() {
return "login";
}
@GetMapping("/chat")
public String chat() {
return "chat";
}
}
3.3 客戶端實(shí)現(xiàn)
客戶端使用 React 框架構(gòu)建,并使用 axios 庫(kù)進(jìn)行網(wǎng)絡(luò)請(qǐng)求。具體代碼如下:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-677809.html
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;
4. 總結(jié)
本文介紹了 Websocket 協(xié)議在微服務(wù)架構(gòu)中的應(yīng)用,并以基于 Websocket 的在線聊天室為例,詳細(xì)介紹了服務(wù)端和客戶端的實(shí)現(xiàn)方式。通過(guò)使用 Spring Boot 和 React 等流行的框架,可以方便地構(gòu)建高效穩(wěn)定的基于 Websocket 的微服務(wù)應(yīng)用。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-677809.html
到了這里,關(guān)于從零開(kāi)始,手把手教你實(shí)現(xiàn)基于 Websocket 的微服務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!