網關的作用
在微服務架構下,單體應用被分割成多個微服務,如果將所有的微服務直接對外暴露,會出現一些安全問題,全部做鑑權處理的話,不光效率底下,而且管理起來更是複雜,而且有一些服務協議不是Web友好的協議。
爲了解決上述問題,出現了使用API網管的解決方案。API網關自身也是一個服務,並且是後端服務的唯一入口。從面向對象設計的角度看,它與外觀模式類似。API網關封裝了系統內部架構,爲每個客戶端提供一個定製的API。除此之外,它還可以負責身份驗證、監控、負載均衡、限流、降級與應用檢測等功能。
Spring Cloud Gateway 簡介
Spring Cloud Gateway是Spring官方基於Spring 5.0、Spring Boot 2.0和ProjectReactor等技術開發的網關,Spring Cloud Gateway旨在爲微服務架構提供簡單、有效且統一的API路由管理方式。Spring Cloud Gateway作爲Spring Cloud生態系中的網關
Spring Cloud Gateway依賴Spring Boot和Spring WebFlux,基於Netty運行。它不能在傳統的servlet容器中工作,也不能構建成war包。
Gateway中最重要的幾個概念:
- 路由(route):路由是網關最基礎的部分,路由信息由一個ID、一個目的url、一組斷言工廠和一組Filter組成。如果路由斷言爲真,則說明請求的url和配置的路由匹配。
- 斷言(Predicate)。Java 8中的斷言函數。Spring Cloud Gateway中的斷言函數輸入類型是Spring 5.0框架中的ServerWebExchange。Spring CloudGateway中的斷言函數允許開發者去定義匹配來自於Http Request中的任何信息,比如請求頭和參數等。
- 過濾器(filter)。一個標準的Spring webFilter。Spring Cloud Gateway中的Filter分爲兩種類型的Filter,分別是Gateway Filter和Global Filter。過濾器Filter將會對請求和響應進行修改處理。
基礎應用
創建一個新的consul-gateway用作API網關,和之前的consul-consumer作爲服務,服務註冊到了Consul上,通過請求網管獲取服務
Consul的使用和consul-consumer的創建可以看之前文章:Spring Cloud: 註冊中心Consul使用
1. 新建一個項目consul-gateway
依賴如下, 添加consul-config作爲配置中心:
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway:2.2.2.RELEASE'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery:2.2.2.RELEASE'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-config:2.2.2.RELEASE'
編寫配置文件, bootstrap.yml:
spring:
application:
name: consul-gateway
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true
service-name: ${spring.application.name}
config:
format: yaml # 配置各式yaml或properties
profile-separator: ':' # 配置分隔符,默認爲“,”
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
啓動類不需要修改。
成功添加到註冊中心。
Gateway的各種網管功能配置用起來很舒服,故意避開了代碼編寫,可以直接通過配置文件進行編寫,這樣的話只要維護修改配置文件就可以更改網管的路由篩選邏輯,配置文件再通過配置中心統一管理,邏輯更加方便維護管理。
2. 配置文件
application. yml:
server:
port: 8730
spring:
cloud:
gateway:
routes:
- id: path_route
uri: http://localhost:8710
predicates:
- Path=/feign
- id: path_route
uri: https://blog.csdn.net
predicates:
- Path=/tonydz0523/**
這裏直接在配置文件中編寫路由邏輯:
- id: path_route
uri: http://localhost:8710
predicates:
- Path=/feign
http://localhost:8710
是consumer的地址- Path=/feign
是可以跳轉的路徑- 當你訪問
http://localhost:8730/feign
就會跳轉到http://localhost:8710/feign
如果需要支持多級Path的話只要加上**即可:
- id: path_route
uri: https://blog.csdn.net
predicates:
- Path=/tonydz0523/**
訪問http://localhost:8730/tonydz0523/article/details/106551483
就會跳轉到http://blog.csdn.net/tonydz0523/article/details/106551483
3. 獲取Consul註冊服務
首先要先開啓locator功能:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
然後添加route規則:
- id: consul-consumer
uri: lb://consul-consumer
predicates:
- Path=/consul-consumer/**
uri以lb://開頭(lb代表從註冊中心獲取服務),後面接的就是你需要轉發到的服務名稱,這個服務名稱必須跟Consul中的對應,否則會找不到服務
通過訪問http://localhost:8730/consul-consumer/feign
即可通過consul註冊中心跳轉到consul-consumer服務:
由於我註冊在Consul上的兩個consul-consumer其中又一個沒有寫feign路徑的服務,因此一個訪問沒有結果。
Gateway路由斷言工廠
After路由斷言
在設置的After時間之後可以進行轉發,否者不可以
- id: after_route
uri: https://example.org
predicates:
- After=2020-06-06T16:32:12.975035+08:00[Asia/Shanghai]
時間可以ZonedDateTime
通過獲得:
ZonedDateTime.now().format(DateTimeFormatter.ISO_ZONED_DATE_TIME);
Before路由斷言
在設置的Before時間之後可以進行轉發,否者不可以
- id: before_route
uri: https://example.org
predicates:
- Before=2020-06-06T16:32:12.975035+08:00[Asia/Shanghai]
Between路由斷言
設置一個時間段,訪問時間在這個時間段的話可以跳轉,兩個時間通過,
隔開
- id: between_route
uri: https://example.org
predicates:
- Between=2020-06-06T16:32:12.975035+08:00[Asia/Shanghai],2020-06-07T16:32:12.975035+08:00[Asia/Shanghai]
Cookie路由斷言
cookie名稱對應的key和value。當請求中攜帶的cookie和Cookied斷言工廠中配置的cookie一致,則路由匹配成功,否則匹配不成功;key和value通過,
隔開,value位置可以是正則表達式用來匹配value
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
Header路由斷言
Header路由斷言工廠用於根據配置的路由header信息進行斷言匹配路由,匹配成功進行轉發,否則不進行轉發。key和value通過,
通過,
隔開,value位置可以是正則表達式用來匹配value
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
Host路由斷言
Host路由斷言工廠根據配置的Host,對請求中的Host進行斷言處理,斷言成功則進行路由轉發,否則不轉發。可以使用**模糊匹配,而且添加多個通過,
隔開
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
Method路由斷言
Method路由斷言工廠會根據路由信息配置的method對請求方法是Get或者Post等進行斷言匹配
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
只有GET和POST請求可以轉發
Path路由斷言
Path路由斷言工廠接收一個參數,根據Path定義好的規則來判斷訪問的URI是否匹配
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment},/yellow/**
如果請求路徑爲/red/xxx可以通過匹配,也可以使用正則進行匹配,如/yellow/**
Query路由斷言
Query路由斷言工廠會從請求中獲取兩個參數,將請求中參數和Query斷言路由中的配置進行匹配,一致則轉發成功,否則轉發失敗
- id: query_route
uri: https://example.org
predicates:
- Query=green, re.
兩個參數一個必需的參數和一個可選的正則表達式, https://example.org?green=rex
可以匹配
RemoteAddr路由斷言
RemoteAddr路由斷言工廠配置一個IPv4或IPv6網段的字符串或者IP。當請求IP地址在網段之內或者和配置的IP相同,則表示匹配成功,成功轉發,否則不能轉發。例如192.1680.1/16是一個網段,其中192.168.0.1是IP地址,16是子網掩碼,當然也可以直接配置一個IP。
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1
Weight路由斷言
Weight路由斷言工程接收兩個參數:group和
weight。通過group將多個uri分爲一組,weight則是權重值
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
route會將約80%的流量轉發至weighthigh.org,並將約20%的流量轉發至weightlow.org。
Gateway內置的Filter
Spring Cloud Gatewat中內置很多的路由過濾工廠,當然可以自己根據實際應用場景需要定製的自己的路由過濾器工廠。路由過濾器允許以某種方式修改請求進來的http請求或返回的http響應。路由過濾器主要作用於需要處理的特定路由。SpringCloud Gateway提供了很多種類的過濾器工廠,過濾器的實現30多個。總得來說,可以分爲七類:Header、Parameter、Path、Status、Redirect跳轉、Hytrix熔斷和RateLimiter
介紹幾種常用的:
AddRequestHeader過濾器
通過名稱我們可以快速明白這個過濾器工廠的作用是添加請求頭。
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
- id: add_request_header_route
uri: https://example.org
predicates:
- Path=/red/{segment}
filters:
- AddRequestHeader=X-Request-Red, Blue-{segment}
符合規則匹配成功的請求,將添加X-Request-red:blue請求頭,將其傳遞到後端服務中,後方服務可以直接獲取請求頭信息。URI變量中的值,可以應用到header中
AddRequestParameter過濾器
AddRequestParameter過濾器作用是對匹配上的請求路由添加請求參數,添加的是一對key和value
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue
添加訪問參數red=blue
RemoveRequestHeader過濾器
RemoveRequestHeader是移除請求頭的過濾器工廠,可以在請求轉發到後端服務之前進行Header的移除操作。與上面相反是將減少請求頭
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
SetStatus過濾器
SetStatus過濾器工廠接收單個狀態,用於設置Http請求的響應碼。它必須是有效的Spring Httpstatus(org.springframework.http.HttpStatus)。它可以是整數值404或枚舉類型NOT_FOUND。
- id: setstatusstring_route
uri: https://example.org
filters:
- SetStatus=BAD_REQUEST
- id: setstatusint_route
uri: https://example.org
filters:
- SetStatus=401
可以通過如下設置以從代理請求返回原始HTTP狀態代碼:
spring:
cloud:
gateway:
set-status:
original-status-header-name: original-http-status
RewritePath過濾器
這使用Java正則表達式提供了一種靈活的方式來重寫請求路徑,兩個參數,前面用來匹配原來路徑,後面是新生成路徑
- id: rewritepath_route
uri: https://example.org
predicates:
- Path=/red/**
filters:
- RewritePath=/red(?<segment>/?.*), $\{segment}
StripPrefix過濾器
StripPrefixGatewayFilterFactory是一個對針對請求url前綴進行處理的filter工廠,用於去除前綴。而PrefixPathGatewayFilterFactory是用於增加前綴。
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
用於減少前綴,如https://blog.csdn.net/tonydz0523/article/details/106551483
減少兩個前綴->https://blog.csdn.net/details/106551483
RedirectTo過濾器
用於重定向操作,工廠有兩個參數,status
和url
。該status
參數應該是300系列重定向HTTP代碼,例如301。該url
參數應該是有效的URL。
- id: prefixpath_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
Retry過濾器
網關作爲所有請求流量的入口,網關對路由進行協議適配和協議轉發處理的過程中,如果出現異常或網絡抖動,爲了保證後端服務請求的高可用,一般處理方式會對網絡請求進行重試,Retry過濾器包含如下參數:
retries
:應嘗試的重試次數。statuses
:應重試的HTTP狀態代碼,以表示org.springframework.http.HttpStatus
。methods
:應該重試的HTTP方法,以表示org.springframework.http.HttpMethod
。series
:可以retry的狀態,使用表示org.springframework.http.HttpStatus.Series
。exceptions
:可以激活retry的異常列表。backoff
:爲重試配置的指數補償。重試在的間隔後執行firstBackoff * (factor ^ n)
,其中n
爲迭代。如果maxBackoff
已配置,則應用的最大退避限制爲maxBackoff
。如果basedOnPreviousValue
爲true,則使用prevBackoff * factor
計算間隔。
默認配置如下:
retries
:3次series
:5XX系列methods
:GET方法exceptions
:IOException
和TimeoutException
backoff
:禁用
- id: retry_test
uri: http://localhost:8080/flakey
predicates:
- Host=*.retry.com
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
Hystrix過濾器
Hystrix的相關內容,請看之前文章:SpringCloud: 熔斷器Hystrix 、Turbine (多圖)
需要一個name
參數,它是的名稱HystrixCommand
- id: hystrix_route
uri: https://example.org
filters:
- Hystrix=myCommandName
Hystrix過濾器還可以接受可選fallbackUri
參數
- id: hystrix_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingserviceendpoint
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/incaseoffailureusethis
- RewritePath=/consumingserviceendpoint, /backingserviceendpoint
默認過濾器
要添加過濾器並將其應用於所有路由,可以使用spring.cloud.gateway.default-filters
。此屬性採用過濾器列表
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Red, Default-Blue
- PrefixPath=/httpbin
Cors配置
您可以配置網關以控制CORS行爲。“全局” CORS配置是URL模式到CorsConfiguration
的映射。以下示例配置了CORS:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "https://docs.spring.io"
allowedMethods:
- GET
RequestRateLimiter
待補充
GlobalFilter
待補充