WebSocket协议概念
WebSocket是一种网络传输协议,可在单个TCP连接上进行全双工通信,位于OSI模型的应用层。WebSocket协议在2011年由IETF标准化为RFC 6455,后由RFC 7936补充规范。Web IDL中的WebSocket API由W3C标准化。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
上面是维基百科对WebSocket协议的解释,简单的来说就是WebSocket协议与HTTP协议类似都是应用层的协议,只是WebSocket协议是用来解决应用层持久通信的问题。
Streaming Text Oriented Messaging Protocol协议,即STOMP协议。这就是WebSocket的一个子协议,主要就是简化标准的WebSocket开发而生的子协议。
Simple (or Streaming) Text Oriented Message Protocol (STOMP), formerly known as TTMP, is a simple text-based protocol, designed for working with message-oriented middleware (MOM). It provides an interoperable wire format that allows STOMP clients to talk with any message broker supporting the protocol.
STOMP协议从命名就可以看出只能传传简单的文本。
pom.xml
主要依赖:
dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-websocketartifactId>
dependency>
配置STOMP的对外端点,接入url等信息:
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Value("${websocket.domain}")
private String domain;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 启用的Broker
config.enableSimpleBroker("/topic");
// 设置客户端的发送消息前缀url
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 对外的端点url
registry.addEndpoint("/gs-guide-websocket").setAllowedOriginPatterns(String.format("https://*.%s", domain))withSockJS();
}
}
需要注意这里的Origin策略控制设置,如果这里不设置你自己的域名,则会出现在https情况下403问题,而http情况下stomp协议能够正常使用的情况。
主要有两种方式,一种是使用Spring注解,一种是Spring编程的方式向客户端发送消息。
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;
@Controller
public class GreetingController {
// 接受客户端发送过来的url,即/app/hello
@MessageMapping("/hello")
// 客户端订阅主题
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
}
}
再来看看编码方式的实现:
@Resource private SimpMessagingTemplate simpMessagingTemplate;
使用:
simpMessagingTemplate.convertAndSend("/topic/greetings", "Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
编程方式主要就是使用SimpMessagingTemplate
,编程方式应用的场景多一些。
public class Greeting {
private String content;
public Greeting() {
}
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
public class HelloMessage {
private String name;
public HelloMessage() {
}
public HelloMessage(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在来看前端这边是怎么处理的:
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}
Spring的websocket stomp Demo项目地址
在网上找了一大圈,也没有找到调试STOMP协议的好工具,调试WebSocket工具倒是有不少。