Spring 云网关:与 HTTP(S) 位于同一 URL 上的 Websockets

Spring cloud gateway: Websockets on the same URL as HTTP(S)

提问人:David North 提问时间:10/31/2023 最后编辑:Anish B.David North 更新时间:11/20/2023 访问量:149

问:

我正在使用Spring Cloud Gateway,路由配置如下:

spring:
  cloud:
    gateway:
      routes:
      - id: http
        uri: http://kubernetes-ingres-controller

换句话说,我将所有路径发送到其他地方,这恰好是 K8s 入口控制器。Spring 添加了一些标头,并处理会话 cookie 到持有者令牌的转换。

我开始添加一些处理 websocket 的端点。但是,由于我们使用 websocket 来执行 GraphQL 订阅,因此我们倾向于使用单个 /graphql 路径来处理普通的 GraphQL 查询和订阅的 websocket。

有没有办法将 Spring Cloud Gateway 配置为在单个路径上同时支持 http 和 ws(或 https 和 wss)?

我可以这样做:

spring:
  cloud:
    gateway:
      routes:
      - id: http
        uri: http://kubernetes-ingres-controller
      - id: ws
        uri: ws://kubernetes-ingres-controller
        predicates:
          - Path=/graphql

但是,我不清楚普通的 HTTP 是否会在 graphql 路径上运行 - 实际上有很多这样的路径;我宁愿不必一一列举。

允许在单个路由上选择性升级到 wss 的 http 的某种设置将是理想的。

java 弹簧云 spring-cloud网关

评论

0赞 Huu Phuong Vu 11/15/2023
我不确定我是否能理解这个问题。在我看来,问题在于有两条路由具有重叠的传入路径(和)。如果是这种情况,您可以使用它来控制两条路线的流量。//graphqlorder
0赞 Mor Blau 11/16/2023
您是否尝试过使用标头作为谓词?Websocket 握手始终包含专用标头 - 'Sec-WebSocket-Key'、'Sec-WebSocket-Protocol'、'Sec-WebSocket-Version' 和 'Upgrade: websocket', 'Connection: upgrade'

答:

0赞 Rajesh P 11/20/2023 #1

我的答案是概念性的,这将有助于你的工作。

  1. 编写一个新类并扩展 AbstractRoutePredicateFactory,如 WebSocketPredicateFactory

  2. 使用你自己的逻辑添加以下代码,以确定请求需要 是否升级到 Web 套接字

  3. 需要更新 yaml 文件以配置路由以使用此 自定义谓词工厂

     @override   
    
    public Predicate apply(Config config) {
               return exchange -> {
                     // Check if the incoming request is for WebSocket upgrade
                    if (isWebSocketUpgradeRequest(exchange)) {
                         exchange.getRequest().mutate().headers(httpHeaders -> 
                          httpHeaders.setUpgrade("websocket"));
    
                   exchange.getResponse().getHeaders().setUpgrade("websocket");
                    return true;
                }
                return false;
            };
        }
    
        private boolean isWebSocketUpgradeRequest(ServerWebExchange exchange) {
            // Implement your own logic to determine WebSocket upgrade based on path, headers, etc.
            // For example:
            return exchange.getRequest().getURI().getPath().equals("/graphql") &&
                    exchange.getRequest().getHeaders().getUpgrade() != null &&
                    exchange.getRequest().getHeaders().getUpgrade().contains("websocket");
        }
    
    

Update the route also like below

spring: cloud: gateway: routes: - id: http-and-ws uri: http://kubernetes-ingres-controller predicates: - name: WebSocketPredicateFactory args: # any orgs