0%

spring-gateway转发websocket

Spring Gateway 介绍

This project provides a library for building an API Gateway on top of Spring MVC. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.


Spring Cloud Gateway features:

  • Built on Spring Framework 5, Project Reactor and Spring Boot 2.0

  • Able to match routes on any request attribute.

  • Predicates and filters are specific to routes.

  • Hystrix Circuit Breaker integration.

  • Spring Cloud DiscoveryClient integration

  • Easy to write Predicates and Filters

  • Request Rate Limiting

  • Path Rewriting

    Spring Gateway 配置

MAVEN依赖添加:

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

Applicaton.yml配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: provider-websocket
uri: lb:ws://provider-websocket
order: 9000
predicates:
- Path=/websocket/**

Spring Gateway 解决info请求

The SockJS client begins by sending “GET /info” to obtain basic information from the server. After that it must decide what transport to use. If possible WebSocket is used. If not, in most browsers there is at least one HTTP streaming option and if not then HTTP (long) polling is used.

SockJS连接前需要发送”Get /info”请求获取服务器相关信息,决定采用何种协议,因此gateway需要对info请求进行处理:

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
@Component
public class WebSocketFilter implements GlobalFilter, Ordered {
private final static String DEFAULT_FILTER_PATH = "/websocket/info";

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String upgrade = exchange.getRequest().getHeaders().getUpgrade();
//log.debug("Upgrade : {}", upgrade);
URI requestUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
//log.debug("path: {}", requestUrl.getPath());
String scheme = requestUrl.getScheme();
if (!"ws".equals(scheme) && !"wss".equals(scheme)) {
return chain.filter(exchange);
} else if (DEFAULT_FILTER_PATH.equals(requestUrl.getPath())) {
String wsScheme = convertWsToHttp(scheme);
URI wsRequestUrl = UriComponentsBuilder.fromUri(requestUrl).scheme(wsScheme).build().toUri();
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, wsRequestUrl);
}
return chain.filter(exchange);
}

@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 2;
}

static String convertWsToHttp(String scheme) {
scheme = scheme.toLowerCase();
return "ws".equals(scheme) ? "http" : "wss".equals(scheme) ? "https" : scheme;
}
您的支持是对我最大的动力 (●'◡'●)