最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決SpringCloud Gateway配置自定義路由404的坑

 更新時(shí)間:2021年09月02日 11:57:04   作者:小卡向前沖  
這篇文章主要介紹了解決SpringCloud Gateway配置自定義路由404的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

問(wèn)題背景

將原有項(xiàng)目中的websocket模塊遷移到基于SpringCloud Alibaba的微服務(wù)系統(tǒng)中,其中網(wǎng)關(guān)部分使用的是gateway。

問(wèn)題現(xiàn)象

遷移后,我們?cè)谑褂每蛻舳诉B接websocket時(shí)報(bào)錯(cuò):

io.netty.handler.codec.http.websocketx.WebSocketHandshakeException: Invalid subprotocol. Actual: null. Expected one of: protocol

...

同時(shí),我們還有一個(gè)用py寫的程序,用來(lái)模擬客戶端連接,但是程序的websocket連接就是正常的。

解決過(guò)程

1 檢查網(wǎng)關(guān)配置

先開(kāi)始,我們以為是gateway的配置有問(wèn)題。

但是在檢查gateway的route配置后,發(fā)現(xiàn)并沒(méi)有問(wèn)題。很常見(jiàn)的那種。

...
	gateway:
      routes:
        #表示websocket的轉(zhuǎn)發(fā)
        - id: user-service-websocket
          uri: lb:ws://user-service
          predicates:
          	- Path=/user-service/mq/**
          filters:
            - StripPrefix=1

其中,lb指負(fù)載均衡,ws指定websocket協(xié)議。

ps,如果,這里還有其他協(xié)議的相同路徑的請(qǐng)求,也可以直接寫成:

...
gateway:
      routes:
        #表示websocket的轉(zhuǎn)發(fā)
        - id: user-service-websocket
          uri: lb://user-service
          predicates:
          	- Path=/user-service/mq/**
          filters:
            - StripPrefix=1

這樣,其他協(xié)議的請(qǐng)求也可以通過(guò)這個(gè)規(guī)則進(jìn)行轉(zhuǎn)發(fā)了。

2 跟源碼,查找可能的原因

既然gate的配置沒(méi)有問(wèn)題,那我們就嘗試從源碼的角度,看看gateway是如何處理ws協(xié)議請(qǐng)求的。

首先,我們要對(duì)“gateway是如何工作的”有個(gè)大概的認(rèn)識(shí):

在這里插入圖片描述

可見(jiàn),在收到請(qǐng)求后,要先經(jīng)過(guò)多個(gè)Filter才會(huì)到達(dá)Proxied Service。其中,要有自定義的Filter也有全局的Filter,全局的filter可以通過(guò)GET請(qǐng)求/actuator/gateway/globalfilters來(lái)查看

{
  "org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5": 10100,
  "org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
  "org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650": -1,
  "org.springframework.cloud.gateway.filter.ForwardRoutingFilter@106459d9": 2147483647,
  "org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd5e0": 2147483647,
  "org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71d23": 0,
  "org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
  "org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
}

可以看到,其中的WebSocketRoutingFilter似乎與我們這里有關(guān)

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        this.changeSchemeIfIsWebSocketUpgrade(exchange);
        URI requestUrl = (URI)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String scheme = requestUrl.getScheme();
        if (!ServerWebExchangeUtils.isAlreadyRouted(exchange) && ("ws".equals(scheme) || "wss".equals(scheme))) {
            ServerWebExchangeUtils.setAlreadyRouted(exchange);
            HttpHeaders headers = exchange.getRequest().getHeaders();
            HttpHeaders filtered = HttpHeadersFilter.filterRequest(this.getHeadersFilters(), exchange);
            List<String> protocols = headers.get("Sec-WebSocket-Protocol");
            if (protocols != null) {
                protocols = (List)headers.get("Sec-WebSocket-Protocol").stream().flatMap((header) -> {
                    return Arrays.stream(StringUtils.commaDelimitedListToStringArray(header));
                }).map(String::trim).collect(Collectors.toList());
            }
            return this.webSocketService.handleRequest(exchange, new WebsocketRoutingFilter.ProxyWebSocketHandler(requestUrl, this.webSocketClient, filtered, protocols));
        } else {
            return chain.filter(exchange);
        }
    }

以debug模式跟蹤到這里后,可以看到,客戶端請(qǐng)求中,子協(xié)議指定為“protocol”。

netty相關(guān):

  • WebSocketClientHandshaker
  • WebSocketClientHandshakerFactory

這段爛尾了。。。

直接看結(jié)論吧

最后發(fā)現(xiàn)出錯(cuò)的原因是在netty的WebSocketClientHandshanker.finishHandshake

public final void finishHandshake(Channel channel, FullHttpResponse response) {
        this.verify(response);
        String receivedProtocol = response.headers().get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL);
        receivedProtocol = receivedProtocol != null ? receivedProtocol.trim() : null;
        String expectedProtocol = this.expectedSubprotocol != null ? this.expectedSubprotocol : "";
        boolean protocolValid = false;
        if (expectedProtocol.isEmpty() && receivedProtocol == null) {
            protocolValid = true;
            this.setActualSubprotocol(this.expectedSubprotocol);
        } else if (!expectedProtocol.isEmpty() && receivedProtocol != null && !receivedProtocol.isEmpty()) {
            String[] var6 = expectedProtocol.split(",");
            int var7 = var6.length;
            for(int var8 = 0; var8 < var7; ++var8) {
                String protocol = var6[var8];
                if (protocol.trim().equals(receivedProtocol)) {
                    protocolValid = true;
                    this.setActualSubprotocol(receivedProtocol);
                    break;
                }
            }
        }
        if (!protocolValid) {
            throw new WebSocketHandshakeException(String.format("Invalid subprotocol. Actual: %s. Expected one of: %s", receivedProtocol, this.expectedSubprotocol));
        } else {
           ......
        }
    }

這里,當(dāng)期望的子協(xié)議類型非空,而實(shí)際子協(xié)議不屬于期望的子協(xié)議時(shí),會(huì)拋出異常。也就是文章最初提到的那個(gè)。

3 異常原因分析

客戶端在請(qǐng)求時(shí),要求子協(xié)議為“protocol”,而我們的后臺(tái)websocket組件中,并沒(méi)有指定使用這個(gè)子協(xié)議,也就無(wú)法選出使用的哪個(gè)子協(xié)議。因此,在走到finishHandShaker時(shí),netty在檢查子協(xié)議是否匹配時(shí)拋出異常WebSocketHandshakeException。 py的模擬程序中,并沒(méi)有指定子協(xié)議,也就不會(huì)出錯(cuò)。

而在springboot的版本中,由于我們是客戶端直連(通過(guò)nginx轉(zhuǎn)發(fā))到websocket服務(wù)端的,因此也沒(méi)有出錯(cuò)(猜測(cè)是客戶端沒(méi)有檢查子協(xié)議是否合法)。。。

解決方法

在WebSocketServer類的注解@ServerEndpoint中,增加subprotocols={“protocol”}

@ServerEndpoint(value = "/ws/asset",subprotocols = {"protocol"})

隨后由客戶端發(fā)起websocket請(qǐng)求,請(qǐng)求連接成功,未拋出異常。

與客戶端的開(kāi)發(fā)人員交流后,其指出,他們的代碼中,確實(shí)指定了子協(xié)議為“protocol”,當(dāng)時(shí)隨手寫的…

心得

  • 定位問(wèn)題較慢,中間走了不少?gòu)澛?。有?yōu)化的空間;
  • 對(duì)gateway的模型有了更深刻的理解;
  • idea 可以用雙擊Shift鍵來(lái)查找所有類,包括依賴包中的。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java基于命令模式實(shí)現(xiàn)郵局發(fā)信功能詳解

    Java基于命令模式實(shí)現(xiàn)郵局發(fā)信功能詳解

    這篇文章主要介紹了Java基于命令模式實(shí)現(xiàn)郵局發(fā)信功能,較為詳細(xì)的分析了命令行模式的概念、原理并結(jié)合實(shí)例形式分析了Java使用命令行模式實(shí)現(xiàn)郵局發(fā)信功能的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2018-04-04
  • Java實(shí)現(xiàn)微信掃碼登入的實(shí)例代碼

    Java實(shí)現(xiàn)微信掃碼登入的實(shí)例代碼

    這篇文章主要介紹了java實(shí)現(xiàn)微信掃碼登入功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Zookeeper中如何解決zookeeper.out文件輸出位置問(wèn)題

    Zookeeper中如何解決zookeeper.out文件輸出位置問(wèn)題

    這篇文章主要介紹了Zookeeper中如何解決zookeeper.out文件輸出位置問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • java實(shí)現(xiàn)文件上傳到服務(wù)器

    java實(shí)現(xiàn)文件上傳到服務(wù)器

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)文件上傳到服務(wù)器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Idea中添加Maven項(xiàng)目支持scala的詳細(xì)步驟

    Idea中添加Maven項(xiàng)目支持scala的詳細(xì)步驟

    這篇文章主要介紹了Idea中添加Maven項(xiàng)目支持scala,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • IDEA maven項(xiàng)目中刷新依賴的兩種方法小結(jié)

    IDEA maven項(xiàng)目中刷新依賴的兩種方法小結(jié)

    這篇文章主要介紹了IDEA maven項(xiàng)目中刷新依賴的兩種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java實(shí)現(xiàn)公用實(shí)體類轉(zhuǎn)Tree結(jié)構(gòu)

    Java實(shí)現(xiàn)公用實(shí)體類轉(zhuǎn)Tree結(jié)構(gòu)

    這篇文章主要為大家介紹了一個(gè)Java工具類,可以實(shí)現(xiàn)Java公用實(shí)體類轉(zhuǎn)Tree結(jié)構(gòu),文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以參考一下
    2024-10-10
  • SpringMVC學(xué)習(xí)之JSON和全局異常處理詳解

    SpringMVC學(xué)習(xí)之JSON和全局異常處理詳解

    在項(xiàng)目上線之后,往往會(huì)出現(xiàn)一些不可預(yù)料的異常信息,對(duì)于邏輯性或設(shè)計(jì)性問(wèn)題,開(kāi)發(fā)人員或者維護(hù)人員需要通過(guò)日志,查看異常信息并排除異常,這篇文章主要給大家介紹了關(guān)于SpringMVC學(xué)習(xí)之JSON和全局異常處理的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • java編程中自動(dòng)拆箱與自動(dòng)裝箱詳解

    java編程中自動(dòng)拆箱與自動(dòng)裝箱詳解

    這篇文章主要介紹了java編程中自動(dòng)拆箱與自動(dòng)裝箱詳解,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • Java實(shí)現(xiàn)圖形化界面的日歷

    Java實(shí)現(xiàn)圖形化界面的日歷

    這篇文章主要介紹了Java實(shí)現(xiàn)圖形化界面的日歷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評(píng)論

东至县| 绥阳县| 哈巴河县| 安图县| 乐陵市| 海城市| 沁源县| 武义县| 舒城县| 阿荣旗| 门头沟区| 龙胜| 株洲县| 盘山县| 伊通| 南丹县| 阿鲁科尔沁旗| 洛隆县| 北宁市| 甘肃省| 神木县| 潮安县| 元江| 团风县| 保亭| 卢湾区| 浮梁县| 航空| 界首市| 秀山| 蒙城县| 中方县| 拉孜县| 宁国市| 永仁县| 台中市| 太康县| 宝丰县| 绥宁县| 长沙县| 枝江市|