修改spring-cloud-gateway中websocket的Max frame length(默认64K)
在项目中发现spring微服推送websocket消息超过60多KB的时候,websocket连接中断,微服并没有异常日志输出,查看spring-cloud-gateway网关发现一条warn日志
An exception has been observed post termination, use DEBUG level to see the full stack: io.netty.handler.codec.http.websocketx.CorruptedWebSocketFrameException: Max frame length of 65536 has been exceeded.
明显message超出了netty websocket限制的最大帧长度,几经周折。。。。。。
直接上代码:
自定义class 继承ReactorNettyWebSocketClient,并override execute方法
public class MyReactorNettyWebSocketClient extends ReactorNettyWebSocketClient {
private static final Log logger = LogFactory.getLog(MyReactorNettyWebSocketClient.class);
private final HttpClient httpClient;
public MyReactorNettyWebSocketClient() {
this(HttpClient.create());
}
public MyReactorNettyWebSocketClient(HttpClient httpClient) {
Assert.notNull(httpClient, "HttpClient is required");
this.httpClient = httpClient;
}
public HttpClient getHttpClient() {
return this.httpClient;
}
public Mono<Void> execute(URI url, WebSocketHandler handler) {
return this.execute(url, new HttpHeaders(), handler);
}
public Mono<Void> execute(URI url, HttpHeaders requestHeaders, WebSocketHandler handler) {
return ((HttpClient.WebsocketSender)this.getHttpClient().headers((nettyHeaders) -> {
this.setNettyHeaders(requestHeaders, nettyHeaders);
}).websocket(StringUtils.collectionToCommaDelimitedString(handler.getSubProtocols()),524288).uri(url.toString())).handle((inbound, outbound) -> {
HttpHeaders responseHeaders = this.toHttpHeaders(inbound);
String protocol = responseHeaders.getFirst("Sec-WebSocket-Protocol");
HandshakeInfo info = new HandshakeInfo(url, responseHeaders, Mono.empty(), protocol);
NettyDataBufferFactory factory = new NettyDataBufferFactory(outbound.alloc());
WebSocketSession session = new ReactorNettyWebSocketSession(inbound, outbound, info, factory);
if (logger.isDebugEnabled()) {
logger.debug("Started session '" + session.getId() + "' for " + url);
}
return handler.handle(session);
}).doOnRequest((n) -> {
if (logger.isDebugEnabled()) {
logger.debug("Connecting to " + url);
}
}).next();
}
private void setNettyHeaders(HttpHeaders httpHeaders, io.netty.handler.codec.http.HttpHeaders nettyHeaders) {
httpHeaders.forEach(nettyHeaders::set);
}
private HttpHeaders toHttpHeaders(WebsocketInbound inbound) {
HttpHeaders headers = new HttpHeaders();
io.netty.handler.codec.http.HttpHeaders nettyHeaders = inbound.headers();
nettyHeaders.forEach((entry) -> {
String name = (String)entry.getKey();
headers.put(name, nettyHeaders.getAll(name));
});
return headers;
}
}
关键在于
然后排除GatewayAutoConfiguration的自动配置:
@SpringBootApplication(exclude = {
GatewayAutoConfiguration.class})
@EnableDiscoveryClient
public class DatapivotGatewayServerApplication {
public static void main(String[] args) {
SpringApplication.run(DatapivotGatewayServerApplication.class, args);
}
}
自定义GatewayAutoConfiguration,并将其内部类HystrixConfiguration下的ReactorNettyWebSocketClient bean 注入为自定义的MyReactorNettyWebSocketClient:
@Configuration
@ConditionalOnProperty(
name = {
"spring.cloud.gateway.enabled"},
matchIfMissing = true
)
@EnableConfigurationProperties
@AutoConfigureBefore({
HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class})
@AutoConfigureAfter({
GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass({
DispatcherHandler.class