项目场景:
使用SpringCloudGateway作为网关转发Websocket链接到微服务。
问题描述
SpringCloudGateway无法完成Websocket的转发,表现为无法链接。
原因分析:
我遇到的问题具体有两个原因导致。
- 跨域问题
我其实已经配置了,但是少加了一个s,allowedOrigins写成了allowedOrigin
花了我八个小时看源码自闭文章来源:https://www.toymoban.com/news/detail-427067.html
因为SpringGateway有一个默认的跨域Filter:CorsWebFilter。这个过滤器使用DefaultCorsProcessor检查了跨域问题。当调用方的域名非同源并且不在允许列表中时会拒绝访问。文章来源地址https://www.toymoban.com/news/detail-427067.html
@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);
}
- 网关微服务引入了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 <T> 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());
}
}
解决方案:
- 跨域问题
在配置文件中加入以下配置:
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
cors-configurations:
# 这里可以自定义哪些url会匹配跨域定义
'[/**]':
allowedOrigins: "*" # 这里定义允许的跨域host,如果为*则全部允许
allowedMethods: "*" # 同上
allowedHeaders: "*" # 同上
- 引入了tomcat的依赖
检查依赖,如果存在下列依赖需要去除。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
到了这里,关于记录SpringCloudGateway无法完成转发Websocket的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!