公司要把以前一个老的项目通过zuul来路由装发(ps:老项目作为微服务中的一个子服务),而这个老项目里面有用到websocket消息推送,然而不幸的是zuul1对websocket的支持并不友好。百度了一些案例,本来开开心心以为可以得到解决方案,可惜到头来是一场梦。百度出来的例子大多数通过自定义zuul过滤器并设置超时时间来支持webscoket,于是照猫画虎,终究没使老项目的websocket通过zuul来代理推送。
追溯其原因老项目的websocket并没用sock.js或者是通过spring集成的webscoket。下边我分享下几种可能可以通过zuul支持websocket的方案,并在文末附送上,最后我怎么使老项目既能通过zuul路由代理,并也使老项目的websocket消息推送生效的方案
1、方案一:自定义zuul过滤器
@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;
}
具体可以参考
https://www.colabug.com/1894128.html
方案二:通过引入spring-cloud-netflix-zuul-websocket这个jar来实现
ps:这是一个老外写的,这种方案比较适用于项目中原来就没有使用websocket的项目,或者有魄力去把原先的已经有过的websocket的代码重构掉,重构前最好写个demo验证下,不然就坑爹了。。。
具体示例可以通过如下地址查看。
https://github.com/mthizo247/spring-cloud-netflix-zuul-websocket
方案三:坐等zuul2开源
zuul2是支持websocket,只是目前还没开源
方案四:把zuul改成spring-cloud-gateway
这种方案适用于刚开始技术选型,定网关的的时候采用。spring-cloud-gataway是支持webscoket
原理是websocket推送的ws链接依然通过老项目A的ip:port,而非zuul代理的路由链接。不过这边有个问题点是老项目(A,B,C,D...)到时候也是集群化,当老项目通过zuul路由时,webscoket要如何获取本项目A的ip:port,而不能获取到其他项目的(B、C、D)的ip:port?
注:A、B、C、D代表都是同个老项目,只是部署的ip:port不一样
此时可以用loadBalancerClient.choose(“注册在服务中心的服务名称”)来使用
private LoadBalancerClient loadBalancerClient = SpringContextHolder.getBean(LoadBalancerClient.class);
private Environment env = SpringContextHolder.getBean(Environment.class);
public String getServiceInstanceUrl() {
String serverName = env.getProperty("spring.application.name");
ServiceInstance serviceInstance = loadBalancerClient.choose(serverName);
if (serviceInstance != null) {
String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
return url;
}
return null;
}