当前位置: 代码网 > it编程>编程语言>Java > Spring Gateway转发websocket原理

Spring Gateway转发websocket原理

2024年08月01日 Java 我要评论
Spring Cloud Gateway简称Spring Gateway,它可以转发请求到后端微服务。Spring Gateway除了转发HTTP请求,也支持websocket请求。我们看下它是怎么实现的吧。

spring cloud gateway简称spring gateway,它可以转发请求到后端微服务。spring gateway除了转发http请求,也支持websocket请求。我们看下它是怎么实现的吧。

配置支持websocket转发

支持websocket转发,需要用到spring-cloud-starter-gateway ,不要搞错成spring-cloud-starter-gateway-web 。引入maven配置:

<dependency>
    <groupid>org.springframework.cloud</groupid>
    <artifactid>spring-cloud-starter-gateway</artifactid>
    <version>4.1.4</version>
</dependency>

然后注册需要路由的规则,可以通过yml配置。

spring:
  cloud:
    gateway:
      routes:
        - id: ws1
          uri: ws://localhost:8080
          predicates:
            - path=/ws

java配置方式,与yml方式等效。

@bean
public routelocator customroutelocator(routelocatorbuilder builder) {
    return builder.routes()
            .route("ws1", r -> r.path("/ws")
                    .uri("ws://localhost:8080"))
            .build();
}

websocket转发原理

处理websocket协议转发的类是org.springframework.cloud.gateway.filter.websocketroutingfilter。它的filter方法会过滤出ws和wss两类请求。

@override
public mono<void> filter(serverwebexchange exchange, gatewayfilterchain chain) {
	changeschemeifiswebsocketupgrade(exchange);

	uri requesturl = exchange.getrequiredattribute(gateway_request_url_attr);
	string scheme = requesturl.getscheme();

	if (isalreadyrouted(exchange) || (!"ws".equals(scheme) && !"wss".equals(scheme))) {
		return chain.filter(exchange);
	}
	setalreadyrouted(exchange);

	httpheaders headers = exchange.getrequest().getheaders();
	httpheaders filtered = filterrequest(getheadersfilters(), exchange);

	list<string> protocols = getprotocols(headers);

	return this.websocketservice.handlerequest(exchange,
			new proxywebsockethandler(requesturl, this.websocketclient, filtered, protocols));
}

可以看到方法的最后一行的handlerequest()方法,exchange是当前发给网关的ws握手请求,proxywebsockethandler用来处理网关和客户端建立完websocket链接成功后的事件。重点看看proxywebsockethandler的handle()方法。


@override
public mono<void> handle(websocketsession session) {
	// pass headers along so custom headers can be sent through
	return client.execute(url, this.headers, new websockethandler() {
	  // 省略部分代码... 
	});
}

handle()方法里用client(websocketclient )给后端websocket地址发来一个握手请求。

到这里,网关握手的流程就清晰了。前端客户端 —[连接]—>网关—[连接]—>后端websocket服务,总共会产生2条websocket连接。

然后就是发消息和断开连接的方式,就在上面省略代码里。

new websockethandler() {

	@override
	public mono<void> handle(websocketsession proxysession) {
		mono<void> serverclose = proxysession.closestatus().filter(__ -> session.isopen())
				.map(this::adaptclosestatus).flatmap(session::close);
		mono<void> proxyclose = session.closestatus().filter(__ -> proxysession.isopen())
				.map(this::adaptclosestatus).flatmap(proxysession::close);
		// use retain() for reactor netty
		mono<void> proxysessionsend = proxysession
				.send(session.receive().doonnext(websocketmessage::retain).doonnext(websocketmessage -> {
					if (log.istraceenabled()) {
						log.trace("proxysession(send from client): " + proxysession.getid()
								+ ", corresponding session:" + session.getid() + ", packet: "
								+ websocketmessage.getpayloadastext());
					}
				}));
		// .log("proxysessionsend", level.fine);
		mono<void> serversessionsend = session.send(
				proxysession.receive().doonnext(websocketmessage::retain).doonnext(websocketmessage -> {
					if (log.istraceenabled()) {
						log.trace("session(send from backend): " + session.getid()
								+ ", corresponding proxysession:" + proxysession.getid() + " packet: "
								+ websocketmessage.getpayloadastext());
					}
				}));
		// .log("sessionsend", level.fine);
		// ensure closestatus from one propagates to the other
		mono.when(serverclose, proxyclose).subscribe();
		// complete when both sessions are done
		return mono.zip(proxysessionsend, serversessionsend).then();
	}
}

websocket连接关闭,是serverclose和proxyclose这两行代码,当后端的websocket连接断开时,就会把断开的转发设置到网关的websocket连接上;网关的websocket连接断开时,就会把断开的转发设置到后端的websocket连接上。这样,两个websocket连接的断开状态就一致了。

websocket发送消息,是proxysessionsend和serversessionsend这两行代码,当网关收到客户端消息时,就会把消息发送给后端websocket服务;当网关收到后端websocket发来的消息时,就会把消息转发给客户端。

至此,网关在websocket连接、发消息、断开连接就和后端websocket服务保持一致了。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com