Spring Boot教程(15) – 使用WebSocket

WebSocket是一种网络通讯协议,一个TCP连接的两端,可以同时给对方发送消息,即支持全双工通信。比较常见的应用场景就是服务端给客户端推送信息,相对于轮询,WebSocket减少了宽带资源浪费,实时性更强。

WebSocket利用了HTTP协议,建立连接之后,会先发一个特殊的HTTP请求过去,服务器发现这是个WebSocket的请求之后,就按照协议要求返回一个特殊的HTTP响应,告诉客户端“我知道你想用WebSocket了,我们按照它的协议来工作吧”。然后TCP链接就不会断开了,留着发消息。所以说WebSocket只利用你原来的80端口(ws://)和443端口(wss://)就可以工作,不需要再开个端口。

在Spring Boot中,你可以添加WebSocket Starter来引入WebSocket的支持:

在你的@Configuration配置类上,添加@EnableWebSocket注解开启此功能。然后还需要进行配置,你要么自己提供个WebSocketConfigurer类型的Bean,要么让@Configuration配置类实现WebSocketConfigurer接口:

registerWebSocketHandlers方法告诉框架,哪个路径是WebSocket的路径,哪个对象用来处理连接和接收信息。按照上图配置过之后,可以通过ws://localhost:8080/api/websocket来连接。上图还提供了一个WSHandler对象,它是用来处理连接和接收消息的:

WSHandler实现了WebSocketHandler接口,在WebSocket连接建立或者断开、收到消息或者收到错误的时候这些方法会被调用。如果你感觉回调太多或者不好用,可以继承AbstractWebSocketHandler类,只实现自己想要的方法:

WebSocket可以发送文本消息或者二进制消息,如果你只关心文本消息的话,只需要保留上图中的handleTextMessage方法就行。好了,到这一步,你的WebSocket已经配置好了,可以使用了:

wsc是一个简易的命令行WebSocket客户端,图中显示连接成功,已经可以发送数据或者接收数据了。通常来说,你的客户端可能是Android或者iOS应用,也很有可能是网页,我们在浏览器的console里试一试:

好像不行哎。图中提示为“Unexpected response code: 403”,403代表禁止访问。为啥禁止访问呢?明明服务器已经搭建好了呀。查看debug log,你会发现出问题的地方:Handshake request rejected, Origin header value https://www.google.com not allowed

上一篇文章中,我们介绍了浏览器的同源策略和跨域访问的问题。Spring Boot的WebSocket支持也是需要配置跨域访问的,否则会返回403。还好配置很简单:

setAllowOrigins还可以传入多个域(协议,域名,端口)。传入*表示允许所有域连接。通常你哪个网站需要连接,就传入哪个域,比如上面图片中的“https://google.com”

既然两边可以收发消息了,那么你就自己定义消息格式就行了,比较简单的做法是使用文本消息,发送JSON对象。你也可以使用STOMP来作为两边的信息交换协议,Spring MVC官方文档也作了介绍,我因为没有实践过,就不多说了。


再说个实际应用中的问题吧,很多公司可能使用nginx作为反向代理,将请求发送到实际的内网服务器上。但是nginx默认情况下不会转发ConnectionUpgrade首部(Header),导致WebSocket无法正常工作,nginx官方文档里已经说明了如何通过配置来解决。同时,你肯定会遇到连接60s后自动断开的问题,因为nginx默认60秒发现没有数据传送,就会关闭连接,你可以通过proxy_read_timeout指令把这一时间延长。

发表评论

电子邮件地址不会被公开。