WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。
那么为什么使用WebSocket
在过去网站为了实现即时通讯,所用的技术都是轮询(polling)。即在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端。这种传统的HTTP请求的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽。 而比较新的技术去做轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通信,但依然需要发出请求。 在 WebSocketAPI,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket 协议中,为我们实现即时服务带来了两大好处:
- Header 互相沟通的Header是很小的-大概只有 2 Bytes
- Server Push
WebSocket的使用
服务端开放API
- 引入springboot对WebSocket支持所需要的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 配置应用中WebSocket的endpoint
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
super.configureMessageBroker(registry);
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/msg");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/bl").withSockJS();
}
}
- API示例
@MessageMapping("/bl")
@SendTo("/topic/notify")
public Map<String, String> noti() {
Map<String, String> map = new HashMap<String, String>();
String msg = UUID.randomUUID().toString();
map.put("msg", msg);
return map;
}
客户端调用websocket
sockjs.js
stomp.js
html部分
<div>
<div>
<button id="connect" onclick="connect();">Connect</button>
<button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button>
</div>
<div id="conversationDiv">
<label>What is your name?</label><input type="text" id="name" />
<button id="sendName" onclick="sendName();">Send</button>
<p id="response"></p>
</div>
</div>
javascript部分
var stompClient = null;
function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
document.getElementById('response').innerHTML = '';
}
function connect() {
var socket = new SockJS('http://localhost:8080/bl');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
stompClient.subscribe('/topic/notify', function(greeting){
showGreeting(JSON.parse(greeting.body).result);
});
});
}
function disconnect() {
stompClient.disconnect();
setConnected(false);
console.log("Disconnected");
}
function sendName() {
var name = document.getElementById('name').value;
stompClient.send("/msg/bl", {}, JSON.stringify({ 'name': name }));
}
function showGreeting(message) {
var response = document.getElementById('response');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(message));
response.appendChild(p);
}
WebSocket跨域
registry.addEndpoint("/bl").setAllowedOrigins("http://www.buglife.cn").withSockJS();