近期的项目中需要用到WebSocket,因为使用的是微服务架构,所以又直接使用了Spring Cloud的Zuul。然而,Zuul对WebSocket的支持不是那么友好,具体可以参考:https://github.com/spring-cloud/spring-cloud-netflix/issues/163。
Spring已经给我们提供了一套WebSockets的解决方案。我们需要用到的有:Sock.js、STOMP、Spring Messaging以及Spring Integration。
Sock.js
Sock.js是一个JavaScript代码库,提供WebSocket-like对象、跨浏览器的JavaScript的API。它在浏览器和web服务器之间创建了一个低延迟、全双工、跨域通信通道。在低版本的浏览器不支持WebSocket时,它可以使用其他协议来处理。
STOMP
STOMP是一种简单的(或流媒体)的消息传递协议。在多种语言、平台和代理之间提供简单和广泛的消息互操作性。
Spring组件
我们在项目中大量使用Spring组件,在这里我们使用到了Spring Messaging和Spring Integration。
Spring Messaging和Spring Integration具体与SockJs、STOMP组合使用可以参考:
https://spring.io/guides/gs/messaging-stomp-websocket/
http://assets.spring.io/wp/WebSocketBlogPost.html
Zuul中的处理
在使用Zuul作为网关的时候,因为我们使用的是Sock.js,所以它可以算得上是支持了。但是为了能够更保险些,需要写一个Filter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
@Component public class WebSocketFilter extends ZuulFilter { @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); String upgradeHeader = request.getHeader("Upgrade"); if (null == upgradeHeader) { upgradeHeader = request.getHeader("upgrade"); } if (null != upgradeHeader && "websocket".equalsIgnoreCase(upgradeHeader)) { context.addZuulRequestHeader("connection", "Upgrade"); } return null; } } |
Spring WebSockets默认的心跳时间是25s,为了能够不被认为是连接超时,我们需要在Zuul中设置比较长的超时时间。
1 2 3 4 5 6 7 8 9 10 11 |
hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 60000 #设置API网关中路由转发请求的HystrixCommand执行超时时间 ribbon: ConnectTimeout: 3000 #设置路由转发请求的时候,创建请求连接的超时时间 ReadTimeout: 60000 #用来设置路由转发请求的超时时间 |
以上,基本上是完成了Zuul与WebSockets之间的代理了。