我在使用Spring Gateway時遇到的一些坑

前言

最近在公司用Spring Cloud 全家桶搭建一套完整的微服務,在網關選型的時候,由於咱們公司可能會用到websocket,因此放棄zuul而改用Spring Cloud Gateway,本文記錄下在使用gateway過程當中遇到的一些坑和注意點。html

正文

Gateway的介紹和基本的搭建就不說了,能夠按照官方文檔走。Spring Cloud Gateway和zuul的區別也不提了,網上也有不少文章。使用gateway直接引入依賴就行,不用在啓動類加註解。linux

1. 請求轉發

我在這裏把請求轉發大概的分紅兩類:nginx

a.未整合註冊中心

其實這種用法比較少,通常來講咱們都會整合註冊中心使用,這樣能夠達到自動配置自動轉發。固然這種特定的方式也許某些場合也會用到。web

這種狀況下就須要你指定你須要轉發到哪一個服務器上去,這邊能夠分爲兩種,配置文件和代碼形式。spring

a.1 配置文件docker

來個樣例api

spring:
  application:
    name: spring-cloud-gateway-sample
  cloud:
    gateway:
      routes:
        - id: blog
          uri: http://juejin.im
          predicates:
            # 匹配路徑轉發
            - Path=/api-boot-datasource-switch.html
# 端口號
server:
  port: 9090
複製代碼

幾個名詞, id是目前所寫的路由的id,id前面有個 -, 這是yml的寫法,至關於一個list的多個元素,你能夠寫多個路由,用-id 來區別開來。跨域

uri就是你須要轉發的地址了。由於沒有整合註冊中心因此須要寫全。bash

這裏解釋下 Predicates吧,每個Predicate的使用,你能夠理解爲:當知足這種條件後纔會被轉發,若是是多個,那就是都知足的狀況下被轉發。好比上面的例子就是當訪問http://localhost:9090/api-boot-datasource-switch.html時就會被自動轉發到http://juejin.im/api-boot-datasource-switch.html,這裏要注意徹底匹配Path的值時纔會進行路由轉發。服務器

因此上面的例子是謂詞Path的樣例,還有不少謂詞,好比 Before, After,Cookie, Header, Host等等,他們也能夠組合出現。 全面的你能夠參考官方文檔或者這篇文章,寫的也比較全面:www.jianshu.com/p/d2c3b6851…

a.2 RouteLocator

代碼的形式能夠經過 RouteLocator 類來實現:

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
  return builder.routes()
    .route("blog", r -> 
           r.path("/api-boot-datasource-switch.html").uri("http://juejin.im"))
    .build();
}
複製代碼

這個就是上面使用Path謂詞的代碼體現,講這個類以@Bean的形式注入到spring中就行。其餘的謂詞相似,不提了。

b.整合註冊中心

這個實際上是平常工做中比較經常使用的,這裏我是用的eureka,其餘的註冊中心應該相似。

這裏我用了配置文件的方式實現了全局的配置,

spring:
  application:
    name: spring-cloud-gateway-sample
  cloud:
    gateway:
      routes:
        - id: blog
          uri: lb://blog-service
          predicates:
            # 匹配路徑轉發
            - Path=/blog/**
# 端口號
server:
  port: 9090
複製代碼

上面的例子和配置未整合時的yml相似,惟一不一樣的就是 uri的配置和Path的條件,這裏使用了 lb:// 的形式,表明從註冊中心獲取服務,後面接的就是你須要轉發到的服務名稱,這個服務名稱必須跟eureka中的對應,不然會找不到服務。因此上面的配置文件就是當你的請求路徑端口號後以/blog開頭的都轉發到 blog-serivce上去,參數不變。

第二種就是我比較推薦的,默認全局的配置,只要你的路徑中以微服務的服務名稱開頭,都會自動轉發到該服務上去。 配置以下

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true

複製代碼

配置完成以後咱們就能夠經過小寫的服務名稱進行訪問了,好比 https://gatewayIp:gatewayPort/blog/article/all 就會自動轉發到 http://blogserviceIp:blogservicePort/article/all

2. 跨域

這個問題,你在其餘平臺幾乎能夠看到千篇一概的解決方案而且親自實踐後發現並無起到做用(多是gateway自升級後這些解法已經不支持,至少我親自實踐後確實不起做用)。不過我仍是遇到了一種比較好的寫法,可以合理的解決跨域的問題,親測有效。若是有更好的解法也歡迎分享。

貼上原文連接: blog.csdn.net/xht555/arti…

另外還有一個,實踐後沒有起到做用,也貼出來你們參考下:www.jianshu.com/p/a46e62f9a…

3. docker容器

我司用docker容器來做爲微服務的linux容器,當容器和spring cloud eureka結合的時候,會遇到一個坑,這是我在使用zuul網關請求的時候就遇到的。

Zuul在轉發請求的時候,會根據eureka註冊表裏的各個微服務的ip+port去尋找地址,可是坑爹的是,當你的微服務在docker容器中時,註冊進去的形式是 docker容器ID + port, 相似於你在eureka的監控面板看到的是 R3FDS4G:8080,這樣你的網關在請求轉發的時候,會報 server unknow 的錯誤,並且這個問題在本地是不存在的由於你本地一直都是localhost。

解決辦法是,在你的eureka client的配置文件中,將你的server 以ip+port的形式註冊進去。

eureka:
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}:${spring.application.name}
複製代碼

好了,當你成功的將你的容器以ip+port的形式註冊到eureka中時,這時候仍是有問題,雖然網關可以成功的將請求轉發,可是這個時候是ping不通的,你點開eureka的監控面板,能夠發現,此時微服務的ip地址並非宿主機的地址。這個其實就要說到docker通訊問題了,docker默認的是bridge模式,容器會本身在內部開闢空間,外部是鏈接不通的。因此docker啓動的時候,須要在命令行里加上 -net=host,這樣容器就會掛載到宿主機上了。關於docker通訊問題能夠自行查閱資料。這個時候網關就能成功的轉發請求了(指的是整個註冊中心)。 若是你使用網關轉發的時候已經指定了微服務的服務器路徑,那就不會出現上述問題的,只是你每多加一個微服務可能就要再次配置一遍。

總結

以上就是我在工做中遇到的一些問題,之後還有問題會更新。

Spring cloud gateway感受國內用的還很少,大廠基本自研,小公司又不多用到spring cloud網關組件或者直接nginx作網關,若是有問題能夠去GitHub直接和做者聊聊。

相關文章
相關標籤/搜索