解决websocket不定时出现1005错误

这篇具有很好参考价值的文章主要介绍了解决websocket不定时出现1005错误。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

后台抛出异常如下:

Operator called default onErrorDropped
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: WebSocket close status code does NOT comply with RFC-6455: 1005
Caused by: java.lang.IllegalArgumentException: WebSocket close status code does NOT comply with RFC-6455: 1005

分析原因是:

spring cloud gateway 转发websocket请求无法监听到 close 事件 没有收到预期的状态码

解决方案:

在gateway进行请求拦截

代码如下:文章来源地址https://www.toymoban.com/news/detail-689920.html

@Slf4j
@Component
public class CustomWebsocketRoutingFilter implements GlobalFilter, Ordered {

    //Sec-Websocket protocol
    public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
    //Sec-Websocket header
    public static final String SEC_WEBSOCKET_HEADER = "sec-websocket";
    //http header schema
    public static final String HEADER_UPGRADE_WebSocket = "websocket";
    public static final String HEADER_UPGRADE_HTTP = "http";
    public static final String HEADER_UPGRADE_HTTPS = "https";
    private final WebSocketClient webSocketClient;
    private final WebSocketService webSocketService;
    private final ObjectProvider<List<HttpHeadersFilter>> headersFiltersProvider;
    // 不直接使用 headersFilters 用该变量代替
    private volatile List<HttpHeadersFilter> headersFilters;

    public CustomWebsocketRoutingFilter(WebSocketClient webSocketClient, WebSocketService webSocketService, ObjectProvider<List<HttpHeadersFilter>> headersFiltersProvider) {
        this.webSocketClient = webSocketClient;
        this.webSocketService = webSocketService;
        this.headersFiltersProvider = headersFiltersProvider;
    }

    /* for testing */
    //http请求转为ws请求
    static String convertHttpToWs(String scheme) {
        scheme = scheme.toLowerCase();
        return "http".equals(scheme) ? "ws" : "https".equals(scheme) ? "wss" : scheme;
    }

    @Override
    public int getOrder() {
        // Before NettyRoutingFilter since this routes certain http requests
        //修改了这里 之前是-1 降低优先级
        return Ordered.LOWEST_PRECEDENCE - 2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        changeSchemeIfIsWebSocketUpgrade(exchange);

        URI requestUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String scheme = requestUrl.getScheme();

        if (ServerWebExchangeUtils.isAlreadyRouted(exchange) || (!"ws".equals(scheme) && !"wss".equals(scheme))) {
            return chain.filter(exchange);
        }
        ServerWebExchangeUtils.setAlreadyRouted(exchange);

        HttpHeaders headers = exchange.getRequest().getHeaders();
        HttpHeaders filtered = HttpHeadersFilter.filterRequest(getHeadersFilters(), exchange);

        List<String> protocols = getProtocols(headers);

        return this.webSocketService.handleRequest(exchange, new ProxyWebSocketHandler(requestUrl, this.webSocketClient, filtered, protocols));
    }

    /* for testing */
    //获取请求头里的协议信息
    List<String> getProtocols(HttpHeaders headers) {
        List<String> protocols = headers.get(SEC_WEBSOCKET_PROTOCOL);
        if (protocols != null) {
            ArrayList<String> updatedProtocols = new ArrayList<>();
            for (int i = 0; i < protocols.size(); i++) {
                String protocol = protocols.get(i);
                updatedProtocols.addAll(Arrays.asList(StringUtils.tokenizeToStringArray(protocol, ",")));
            }
            protocols = updatedProtocols;
        }
        return protocols;
    }

    /* for testing */
    List<HttpHeadersFilter> getHeadersFilters() {
        if (this.headersFilters == null) {
            this.headersFilters = this.headersFiltersProvider.getIfAvailable(ArrayList::new);

            // remove host header unless specifically asked not to
            this.headersFilters.add((headers, exchange) -> {
                HttpHeaders filtered = new HttpHeaders();
                filtered.addAll(headers);
                filtered.remove(HttpHeaders.HOST);
                boolean preserveHost = exchange.getAttributeOrDefault(ServerWebExchangeUtils.PRESERVE_HOST_HEADER_ATTRIBUTE, false);
                if (preserveHost) {
                    String host = exchange.getRequest().getHeaders().getFirst(HttpHeaders.HOST);
                    filtered.add(HttpHeaders.HOST, host);
                }
                return filtered;
            });

            this.headersFilters.add((headers, exchange) -> {
                HttpHeaders filtered = new HttpHeaders();
                for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
                    if (!entry.getKey().toLowerCase().startsWith(SEC_WEBSOCKET_HEADER)) {
                        filtered.addAll(entry.getKey(), entry.getValue());
                    }
                }
                return filtered;
            });
        }

        return this.headersFilters;
    }

    static void changeSchemeIfIsWebSocketUpgrade(ServerWebExchange exchange) {
        // 检查版本是否适合
        URI requestUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String scheme = requestUrl.getScheme().toLowerCase();
        String upgrade = exchange.getRequest().getHeaders().getUpgrade();
        // change the scheme if the socket client send a "http" or "https"
        if (HEADER_UPGRADE_WebSocket.equalsIgnoreCase(upgrade) && (HEADER_UPGRADE_HTTP.equals(scheme) || HEADER_UPGRADE_HTTPS.equals(scheme))) {
            String wsScheme = convertHttpToWs(scheme);
            boolean encoded = ServerWebExchangeUtils.containsEncodedParts(requestUrl);
            URI wsRequestUrl = UriComponentsBuilder.fromUri(requestUrl).scheme(wsScheme).build(encoded).toUri();
            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, wsRequestUrl);
            if (log.isTraceEnabled()) {
                log.trace("changeSchemeTo:[" + wsRequestUrl + "]");
            }
        }
    }

    //自定义websocket处理方式
    private static class ProxyWebSocketHandler implements WebSocketHandler {

        private final WebSocketClient client;
        private final URI url;
        private final HttpHeaders headers;
        private final List<String> subProtocols;

        ProxyWebSocketHandler(URI url, WebSocketClient client, HttpHeaders headers, List<String> protocols) {
            this.client = client;
            this.url = url;
            this.headers = headers;
            if (protocols != null) {
                this.subProtocols = protocols;
            } else {
                this.subProtocols = Collections.emptyList();
            }
        }

        @Override
        public List<String> getSubProtocols() {
            return this.subProtocols;
        }

        @Override
        public Mono<Void> handle(WebSocketSession session) {
            return this.client.execute(this.url, this.headers, new WebSocketHandler() {
                private CloseStatus adaptCloseStatus(CloseStatus closeStatus) {
                    int code = closeStatus.getCode();
                    if (code > 2999 && code < 5000) {
                        return closeStatus;
                    }
                    switch (code) {
                        case 1000:
                            //正常关闭
                            return closeStatus;
                        case 1001:
                            //服务器挂了或者页面跳转
                            return closeStatus;
                        case 1002:
                            //协议错误
                            return closeStatus;
                        case 1003:
                            //收到了不能处理的数据类型
                            return closeStatus;
                        case 1004:
                            // 预留关闭状态码
                            return CloseStatus.PROTOCOL_ERROR;
                        case 1005:
                            // 预留关闭状态码 期望收到状态码但是没有收到
                            return CloseStatus.PROTOCOL_ERROR;
                        case 1006:
                            // 预留关闭状态码 连接异常关闭
                            return CloseStatus.PROTOCOL_ERROR;
                        case 1007:
                            //收到的数据与实际的消息类型不匹配
                            return closeStatus;
                        case 1008:
                            //收到不符合规则的消息
                            return closeStatus;
                        case 1009:
                            //收到太大的不能处理的消息
                            return closeStatus;
                        case 1010:
                            //client希望server提供多个扩展,server没有返回相应的扩展信息
                            return closeStatus;
                        case 1011:
                            //server遇到不能完成的请求
                            return closeStatus;
                        case 1012:
                            // Not in RFC6455
                            // return CloseStatus.SERVICE_RESTARTED;
                            return CloseStatus.PROTOCOL_ERROR;
                        case 1013:
                            // Not in RFC6455
                            // return CloseStatus.SERVICE_OVERLOAD;
                            return CloseStatus.PROTOCOL_ERROR;
                        case 1015:
                            // 不能进行TLS握手 如:server证书不能验证
                            return CloseStatus.PROTOCOL_ERROR;
                        default:
                            return CloseStatus.PROTOCOL_ERROR;
                    }
                }

                /**
                 * send      发送传出消息
                 * receive   处理入站消息流
                 * doOnNext  对每条消息做什么
                 * zip       加入流
                 * then      返回接收完成时完成的Mono<Void>
                 */
                @Override
                public Mono<Void> handle(WebSocketSession proxySession) {
                    Mono<Void> serverClose = proxySession.closeStatus().filter(__ -> session.isOpen())
                            .map(this::adaptCloseStatus)
                            .flatMap(session::close);
                    Mono<Void> proxyClose = session.closeStatus().filter(__ -> proxySession.isOpen())
                            .map(this::adaptCloseStatus)
                            .flatMap(proxySession::close);
                    // Use retain() for Reactor Netty
                    Mono<Void> proxySessionSend = proxySession
                            .send(session.receive().doOnNext(WebSocketMessage::retain));
                    Mono<Void> serverSessionSend = session
                            .send(proxySession.receive().doOnNext(WebSocketMessage::retain));
                    // Ensure closeStatus from one propagates to the other
                    Mono.when(serverClose, proxyClose).subscribe();
                    // Complete when both sessions are done
                    return Mono.zip(proxySessionSend, serverSessionSend).then();
                }
                @Override
                public List<String> getSubProtocols() {
                    return CustomWebsocketRoutingFilter.ProxyWebSocketHandler.this.subProtocols;
                }
            });
        }
    }


}

到了这里,关于解决websocket不定时出现1005错误的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 解决网络编程中的EOF违反协议问题:requests库与SSL错误案例分析

    1. 问题背景 近期,一个用户在使用requests库进行网络编程时遭遇到了一个不寻常的问题,涉及SSL错误,并提示错误消息为 SSLError(SSLEOFError(8, u\\\'EOF occurred in violation of protocol (_ssl.c:661)\\\'),)) 。该用户表示已经采取了多种方法来解决这个问题,包括更换设备、更新操作系统和库等措

    2024年02月20日
    浏览(49)
  • 电脑连接时出现错误797的原因及解决方法

    有网友说电脑在连接网络的时候,出现错误797的提示,然后通过猫来连接网络也连接不上的情况,可是猫的指示灯显示很正常的。那么 电脑连接时出现错误797要怎么办 呢?今天小编就针对于错误797的来说说其解决方法吧。 故障分析 :连接网络出现797错误的话,一般是电脑

    2024年02月05日
    浏览(51)
  • 花生壳诊断连接时出现1007错误的解决方案

    在内网配置好花生壳客户端后,发现连接失败 经搜索,在这个页面找到了原因,使用2和3中的命令测试都没有得到正确结果,说明DNS有问题 在Linux平台上修改DNS,注意要用sudo获取只读文件的修改权限 首先 sudo vi /etc/resolv.conf 然后添加DNS,我还加了腾讯和阿里的DNS :wq! 强行保存

    2024年02月11日
    浏览(63)
  • 【Navicat 连接MySQL时出现错误1251:客户端不支持服务器请求的身份验证协议;请考虑升级MySQL客户端】

    使用Navicat连接时报1251错误,如下图: Navicat是一款流行的数据库管理工具,它能够方便地连接和管理各种数据库。然而,有时候当我们尝试连接MySQL数据库时,可能会遇到错误1251:客户端不支持服务器请求的身份验证协议的问题。这个问题可能会让一些用户感到困惑,影响到

    2024年02月13日
    浏览(41)
  • sqlserver建立连接时出现与网络相关的或特定于实例的错误

    我们在登录sqlserver时总会遇到这样的错误:  这是由于我们sqlserver代理服务没有打开所引起的,我这里提供两种打开方式: 1、第一中方法就是 :win+R键,输入services.msc找到sqlserver代理服务,点击启动如下图所示: 启动后重新打开sqlserver即可正常连接使用;  2、第二中方法

    2024年02月15日
    浏览(36)
  • 解决Jackson解析JSON时出现的Illegal Character错误

    🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐 🌊 《100天精通Golang(基础入门篇)》学会Golang语言

    2024年02月10日
    浏览(44)
  • 远程桌面时出现“身份验证错误,要求的函数不受支持”解决办法

    CVE-2018-0886 的 CredSSP 更新 - Microsoft 支持 解决办法如下(强烈推荐方法一)。 方法一( 强烈推荐 ): 本地电脑和服务器端都同时安装更新补丁,更新以后重启服务器。 补丁单独下载地址: win 7、win2008 R2:KB4103718  win 8、win2012:KB4103730 win10、win2016 :KB4103721 注意下载对应版本

    2024年02月11日
    浏览(74)
  • UE5发布时出现SDK NOT Setup错误解决方法

    UE5项目打包时出现SDK未设置(SDK NOT SETUP)的弹出错误 原因是缺少了.Net环境,以及没有安装Windows SDK 参考以下视频教程: 【UE5】如何修正SDK Not Setup_哔哩哔哩_bilibili 第一步:下载WindowsSDK 下载地址如下: Windows SDK - Windows应用开发 | Microsoft Developer 下载并安装 第二步:复制ho

    2023年04月16日
    浏览(33)
  • Camera2处理预览回调数据时出现native错误的解决方法

    前言:在使用camera api 2 时,若是增加了回调数据的监听器,那么需要在OnImageAvailableListener回调函数中从ImageReader获取图像,并转化成我们需要的格式(比如使用自己写的yv12转nv21格式的图像格式转化函数),比如NV21格式。在退出预览界面时,有时候会在图像转化格式函数中出现

    2024年02月12日
    浏览(48)
  • 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。

    此情况,介于我已经遇到了无数次,然后每次和开盲盒一样,解决方法都不一样,真的让人抓狂。目前我所遇到的解决办法有3种。 (首先你的密码是正确的,如果密码错误,进入Windows身份验证修改密码) 一、服务名称错误(服务器的ipv4输入错误) 电脑属性中查看ipv4。或者

    2024年02月15日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包