spring cloud gateway网关转发websocket请求

news2025/1/20 10:56:05

springcloud gateway网关是所有微服务的统一入口。

1、springcloud gateway关键术语

  • Route:路由,网关配置的基本组成模块。一个Route模块由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配,目标URI会被访问。
  • Predicate:断言,可以使用它来匹配来自 HTTP 请求的任何内容。
  • Filter:过滤器,可以使用它拦截和修改请求,并且对上游的响应,进行二次处理。过滤器为org.springframework.cloud.gateway.filter.GatewayFilter类的实例。

2、springcloud gateway处理流程
客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
在这里插入图片描述

3、在springcloud gateway网关中,在yml配置文件中通过如下配置对websocket请求进行转发:

spring:
  cloud:
    gateway:
      routes:
        - id: websocket1
          uri: ws://127.0.0.1:9099 #使用方式1:websocket配置,直接地址
          #uri: lb:ws://serviceName #使用方式2:websocket配置,通过nacos注册中心调用serviceName
          predicates: 
            - Path=/websocket

当websocket服务为基于netty的socketio,netty需要单独开端口访问,上面方式要直接指定websocket服务的端口,多个websocket服务时,可以配置多个相同的路由规则,每个指定一个socketio服务,然后通权重实现负载均衡:

spring:
  cloud:
    gateway:
      routes:
        - id: websocket1
          uri: ws://127.0.0.1:8081
          predicates:
            - Path=/socket
            - Weight=group1,50
        - id: websocket2
          uri: ws://127.0.0.1:8082
          predicates:
            - Path=/socket
            - Weight=group1,50
         

4、在springcloud gateway网关中转发websocket请求时,连上websocket后出现立马断开问题,报错java.lang.UnsupportedOperationException,详细如下:

2022-12-26 22:01:23.433 ERROR 12636 --- [ctor-http-nio-6] o.s.w.s.adapter.HttpWebHandlerAdapter    : [6726d297-6] Error [java.lang.UnsupportedOperationException] for HTTP GET "/socket/?EIO=3&transport=websocket", but ServerHttpResponse already committed (200 OK)
2022-12-26 22:01:23.433 ERROR 12636 --- [ctor-http-nio-6] r.n.http.server.HttpServerOperations     : [6726d297-1, L:/10.8.0.78:9999 - R:/10.8.0.78:51969] Error finishing response. Closing connection

java.lang.UnsupportedOperationException: null
	at org.springframework.http.ReadOnlyHttpHeaders.put(ReadOnlyHttpHeaders.java:126) ~[spring-web-5.3.20.jar:5.3.20]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ org.springframework.web.cors.reactive.CorsWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
	
	*__checkpoint ⇢ HTTP GET "/socket/?EIO=3&transport=websocket" [ExceptionHandlingWebHandler]
Original Stack Trace:
		at org.springframework.http.ReadOnlyHttpHeaders.put(ReadOnlyHttpHeaders.java:126) ~[spring-web-5.3.20.jar:5.3.20]

通过分析发现是gateway处理跨域时使用的是如下方式:

        // 跨域配置源
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        //设置跨域的配置信息
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 允许所有请求来源进行跨域
        //corsConfiguration.addAllowedOrigin("*");
        ...

需改成reactor响应式方式,如下:

return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            // 使用SpringMvc自带的跨域检测工具类判断当前请求是否跨域
            if (!CorsUtils.isCorsRequest(request)) {
                return chain.filter(ctx);
            }
            HttpHeaders requestHeaders = request.getHeaders();                                  // 获取请求头
            ServerHttpResponse response = ctx.getResponse();                                    // 获取响应对象
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();          // 获取请求方式对象
            HttpHeaders headers = response.getHeaders();                                        // 获取响应头
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());   // 把请求头中的请求源(协议+ip+端口)添加到响应头中(相当于yml中的allowedOrigins)
            headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
            if (requestMethod != null) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());    // 允许被响应的方法(GET/POST等,相当于yml中的allowedMethods)
            }
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");       // 允许在请求中携带cookie(相当于yml中的allowCredentials)
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");             // 允许在请求中携带的头信息(相当于yml中的allowedHeaders)
            headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "18000L");               // 本次跨域检测的有效期(单位毫秒,相当于yml中的maxAge)
            if (request.getMethod() == HttpMethod.OPTIONS) {                                    // 直接给option请求反回结果
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
            return chain.filter(ctx);                                                           // 不是option请求则放行
        };

5、springcloud gateway处理跨域,可以通过yml配置方式实现,如:

    gateway:
      # 全局的跨域配置
      globalcors:
        # 解决options请求被拦截问题
        add-to-simple-url-handler-mapping: true
        cors-configurations:
          # 拦截的请求
          '[/**]':
            # 允许跨域的请求
            #allowedOrigins: "*" # spring boot2.4以前的配置
            allowedOriginPatterns: "*" # spring boot2.4以后的配置
            # 允许请求中携带的头信息
            allowedHeaders: "*"
            # 运行跨域的请求方式
            allowedMethods: "*"
            # 是否允许携带cookie
            allowCredentials: true
            # 跨域检测的有效期,单位s
            maxAge: 3600

也可以通过编码的方式定义跨域配置类,如:

@Configuration
public class CorsConfig {

    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            // 使用SpringMvc自带的跨域检测工具类判断当前请求是否跨域
            if (!CorsUtils.isCorsRequest(request)) {
                return chain.filter(ctx);
            }
            HttpHeaders requestHeaders = request.getHeaders();                                  // 获取请求头
            ServerHttpResponse response = ctx.getResponse();                                    // 获取响应对象
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();          // 获取请求方式对象
            HttpHeaders headers = response.getHeaders();                                        // 获取响应头
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());   // 把请求头中的请求源(协议+ip+端口)添加到响应头中(相当于yml中的allowedOrigins)
            headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
            if (requestMethod != null) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());    // 允许被响应的方法(GET/POST等,相当于yml中的allowedMethods)
            }
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");       // 允许在请求中携带cookie(相当于yml中的allowCredentials)
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");             // 允许在请求中携带的头信息(相当于yml中的allowedHeaders)
            headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "18000L");               // 本次跨域检测的有效期(单位毫秒,相当于yml中的maxAge)
            if (request.getMethod() == HttpMethod.OPTIONS) {                                    // 直接给option请求反回结果
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
            return chain.filter(ctx);                                                           // 不是option请求则放行
        };
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/116508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

经营报表-FineReport配置Oracle外接数据库(2)

1. 配置外接数据库 1.1 外接数据库配置入口 外接数据库的配置入口,有三种形式: 1)超级管理员第一次登录数据决策系统时,即可为系统配置外接数据库。如下图所示: 2)对于使用内置数据库的系统,管…

蓝桥杯嵌入式|第十三届蓝桥杯嵌入式省赛程序设计试题及其题解

题目 十三届省赛是要制作一个可由串口设置密码的密码锁。在本场比赛中,我们将用到LED模块、按键模块、串口模块、定时器的PWM模块以及官方会提供源码的LCD模块。下面就请看原题: 题解 在正式题解前,大家需要注意以下几点: 由于LCD…

《计算机网络》——第二章知识点

物理层:在连接各种计算机的传输媒体上传输数据比特流,确定与传输媒体接口有关的一些特性。1.机械特性 定义物理连接的特性,规定物理连接时所采用的规格、接口形状、引线数目、引脚数量和排列情况。 2.电气特性 规定传输二进制位时,线路上信…

【深度学习框架TensorFlow】使用TensorFlow框架构建全连接的神经网络,实现手写数字识别

文章目录一.TensorFlow1.1 内容介绍二.开始实验2.1TensorFlow的基本使用2.2基于全连接神经网络的手写数字识别2.3 结论一.TensorFlow 使用深度学习框架TensorFlow。 目标: 1.了解TensorFlow的基本用法; 2.学习使用TensorFlow构建全连接的神经网络&…

双周赛(三)

T1: 如果你仍然再用二指禅打字,那我建议你重新学习打字,这样你打字会更快,感觉更舒适和愉快。 有很多网站教授正确的打字。下图描述了基本原理: 用同一手指按压颜色相同的键。黄色键需要用小指按压,蓝色的用无名指&a…

最新 iOS 更新后 iPhone 联系人和数据丢失/丢失

我两天前做了最新的更新,现在我有丢失的联系人。帮助!! 许多 iPhone 用户犹豫是否将他们的设备升级到最新的 iOS 系统有一个(也许是几个)充分的理由。每次 iOS 发布后,总会有新功能震撼我们的世界。但是&am…

Unity 小积累

** Unity 学习小积累 ** 1.FindObjectsOfType和FindObjectOfType 前者返回所有个体(集合) 后者返回第一个个体 (单个) 2.uinty打包问题 打包webgl遇到了 实际上和py没有关系 c盘不够了 单纯 3.Unity 默认下载位置 坑 1.Uni…

【css样式】页面实现一侧固定一侧滚动的效果,到底部后一起滚动

文章目录position的定位类型position的定位类型 static:默认值,没有定位,遵循正常的文档流 fixed:固定定位,元素的位置是相对于浏览器窗口 relative:相对定位,相对于其正常的位置,移…

BOSS直聘自动投简历的实现过程

这两年疫情,公司业务越来越差,必须得准备后路了,每天睡前都会在直聘上打一遍招呼,一直到打哈欠有睡意为止...,这样持续了一周,发现很难坚持,身为一名资深蜘蛛侠,怎么能这样下去呢?于…

3D模型的生成式AI

生成式 AI 席卷了 2022 年,我们最近决定 Physna 不应错过这个热点。 因此,尽管生成 AI 并不是我们的商业模式—Physna 是一家 3D 搜索和分析公司,专注于 AR/VR 和制造中的工程和设计应用—我们还是决定为 3D 模型和场景生成 AI 构建一个非常基…

Node.js——初识Node.js与内置模块(一)

1.初识 Node.js 1.1 浏览器中的 JavaScript运行环境 1.浏览器中的 JavaScript 的组成部分 2.为什么 JavaScript 可以在浏览器中被执行 3.为什么 JavaScript 可以操作 DOM 和 BOM 4.浏览器中的 JavaScript 运行环境 Javascript可以借助node,js进行后端开发 1.2 Node.js 简介 …

virtio前端驱动通知机制分析

virtio前端驱动通知机制分析 virtio 前后端主要通过PCI配置空间的寄存器来完成通信,I/O 请求的数据地址存放于 vring 中,并通过共享vring这个区域来实现 I/O 请求数据的共享。 由上图可知,虚拟机与主机之间交互用到了两个结构体:p…

智能网联汽车行业发展

智能网 联汽车信息安全发展趋势 智能网联汽车行业发展 根据工信部发布的《国家车联网产业标准体系建设 指南(智能网联汽车)》的定义,智能网联汽车是指搭载先进的车载传感器 、控制器、执行器等装置,并融合现代通信与网络技术&a…

明道云联合思迈特打造会员管理应用可视化联合解决方案

背景介绍 明道云在协助企业数字化转型过程中,发现客户对利用业务数据形成企业级报表和数据可视化大屏的需求十分强烈。为了满足这种需求,企业通常需要成立专门的数据分析团队,但这需要巨大的人力和财力投入,时间周期也较长。为了…

信息数智化招采系统源码——信息数智化招采系统

信息数智化招采系统 服务框架:Spring Cloud、Spring Boot2、Mybatis、OAuth2、Security 前端架构:VUE、Uniapp、Layui、Bootstrap、H5、CSS3 涉及技术:Eureka、Config、Zuul、OAuth2、Security、OSS、Turbine、Zipkin、Feign、Monitor、Stre…

React 学习笔记总结(五)

文章目录1. React 嵌套路由(多级路由)2. params参数 与 query参数3. React路由组件 传递params参数数据4. React路由组件 传递search参数5. React路由组件 传递search参数6. React路由组件 特殊情况: 刷新页面7. React路由 的 push 和 replace8. React的 编程式路由9. React路由…

Transformer架构:位置编码

2017年,Google等人提出了Vaswani提出了一种新颖的纯注意力序列到序列架构,闻名学术界与工业界的Transformer架构横空出世,它的可并行化训练能力和优越的性能称为自然语言处理领域和计算机视觉领域研究人员的热门选择,本文将重点讨…

elasticsearch--Master选举

最近一直在学习elasticsear相关的东西,在这学习的过程中记录一下比较重要的学习内容。方便以后看的时候加深印象。 假如宕机的节点是Master节点 下面是Maste节点选举 的流程图 在findMaster的方法中每隔一段时间就会ping所有的节点,看看有没有哪个节…

java设计模式三

文章目录4) 创建IOC容器相关的类5) 自定义IOC容器测试6) 案例中使用到的设计模式7.2 剖析MyBatis框架中用到的经典设计模式7.2.1 MyBatis回顾7.2.1.1 MyBatis与ORM框架7.2.1.1 MyBatis的基础使用7.2.2 MyBatis中使用到的设计模式7.2.2.1 Builder模式7.2.2.2 工厂模式7.2.2.3 单…

基于Java开发(PC)小说自检测系统【100010061】

Java 语言与系统设计课程(小说自检测系统) 一、目的与要求 ​ 自行下载最喜爱的小说 1 部。存到服务器中,格式自定。一般存储为文本文档。要求长篇小说,20 万字以上。举例说明:下载《三国演义》保存在服务器端。 ​…