记录SpringCloudGateway无法完成转发Websocket的问题

项目场景:

使用SpringCloudGateway作为网关转发Websocket链接到微服务。


问题描述

SpringCloudGateway无法完成Websocket的转发,表现为无法链接。


原因分析:

我遇到的问题具体有两个原因导致。

  1. 跨域问题

我其实已经配置了,但是少加了一个s,allowedOrigins写成了allowedOrigin
花了我八个小时看源码 自闭

因为SpringGateway有一个默认的跨域Filter:CorsWebFilter。这个过滤器使用DefaultCorsProcessor检查了跨域问题。当调用方的域名非同源并且不在允许列表中时会拒绝访问。

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
		ServerHttpRequest request = exchange.getRequest();
		CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(exchange);
		boolean isValid = this.processor.process(corsConfiguration, exchange); // 调用进行跨域验证
		if (!isValid || CorsUtils.isPreFlightRequest(request)) {
			// 非同源且不在允许范围内
			// 不处理(不转发)
			return Mono.empty();
		}
		return chain.filter(exchange);
	}
  1. 网关微服务引入了tomcat的依赖
    SpringGateway使用了Netty作为容器,而Netty天生支持长连接所以可以进行转发。而项目中如果引入了Tomcat的相关依赖则会将容器替换为Tomcat导致无法转发。具体原因是ServerHttpResponseDecorator这个类中的getNativeResponse这个方法会去对响应体进行强制转换,但是Tomcat的Response和Netty的Response不一样,从而导致抛出ClassCastException。
	/**
	 * Return the native response of the underlying server API, if possible,
	 * also unwrapping {@link ServerHttpResponseDecorator} if necessary.
	 * @param response the response to check
	 * @param  the expected native response type
	 * @throws IllegalArgumentException if the native response can't be obtained
	 * @since 5.3.3
	 */
	public static <T> T getNativeResponse(ServerHttpResponse response) {
		if (response instanceof AbstractServerHttpResponse) {
			// 这一段会导致抛出ClassCastException
			return ((AbstractServerHttpResponse) response).getNativeResponse();
		}
		else if (response instanceof ServerHttpResponseDecorator) {
			return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate());
		}
		else {
			throw new IllegalArgumentException(
					"Can't find native response in " + response.getClass().getName());
		}
	}

解决方案:

  1. 跨域问题
    在配置文件中加入以下配置:
spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        cors-configurations:
          # 这里可以自定义哪些url会匹配跨域定义
          '[/**]':
            allowedOrigins: "*"	# 这里定义允许的跨域host,如果为*则全部允许
            allowedMethods: "*"	# 同上
            allowedHeaders: "*"	# 同上
  1. 引入了tomcat的依赖
    检查依赖,如果存在下列依赖需要去除。
<dependency>
	<groupId>javax.servletgroupId>
	<artifactId>javax.servlet-apiartifactId>
dependency>
 <dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
 dependency>
 <dependency>
	<groupId>javax.servletgroupId>
	<artifactId>jstlartifactId>
dependency>
<dependency>
	<groupId>org.apache.tomcat.embedgroupId>
	<artifactId>tomcat-embed-jasperartifactId>
dependency>

你可能感兴趣的:(Web,websocket,java,spring,cloud,微服务,gateway)