由于Zuul 2.x的不斷跳票矿辽,Spring Cloud自行研發(fā)了另外一款服務(wù)網(wǎng)關(guān)產(chǎn)品:Spring Cloud Gateway骏全,并且在最新版本中推薦使用枪芒,所以Gateway出現(xiàn)的原因就是為了代替Zuul掷邦。相比Zuul猪狈,Gateway是Spring體系內(nèi)的產(chǎn)物抛蚁,和Spring融合更好陈醒。同時(shí)相比于Zuul 1.x的阻塞和多線程方式,Gateway采用了Netty異步非阻塞模型篮绿,占用資源更小孵延,性能更有優(yōu)勢(shì)。同時(shí)增加了Predicate和限流等功能亲配。
1 傳統(tǒng)路由方式
創(chuàng)建一個(gè)Spring Boot項(xiàng)目尘应,命名為api-gateway。
1.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>4.0.0org.springframework.bootspring-boot-starter-parent2.1.7.RELEASE<!-- lookup parent from repository -->com.hysapi-gateway0.0.1-SNAPSHOTapi-gatewayDemo project for Spring Cloud 1.8Greenwich.SR2 org.springframework.cloudspring-cloud-starter-gatewayorg.springframework.bootspring-boot-starter-testtest org.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimport org.springframework.bootspring-boot-maven-plugin
1.2 啟動(dòng)類(lèi)
packagecom.hys.apigateway; importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplicationpublicclassApiGatewayApplication{ publicstaticvoidmain(String[] args){? ? ? ? SpringApplication.run(ApiGatewayApplication.class, args);? ? } }
1.3 路由方式
Gateway的路由方式有兩種吼虎,分別為編碼方式和配置方式犬钢。
1.3.1 編碼方式
在上面的啟動(dòng)類(lèi)中加入下面的自定義RouteLocator的方法即可:
@BeanpublicRouteLocatorcustomRouteLocator(RouteLocatorBuilder builder){returnbuilder.routes().route("route_a", r -> r.path("/hello").uri("http://localhost:8081/"))? ? ? ? ? ? ? ? .build();? ? }
1.3.2 配置方式
將上面自定義RouteLocator的方法注釋掉,在application.properties文件中輸入下面的內(nèi)容:
spring.application.name=api-gatewayserver.port=5555spring.cloud.gateway.routes[0].id=route_aspring.cloud.gateway.routes[0].uri=http://localhost:8081/spring.cloud.gateway.routes[0].predicates[0]=Path=/hello
其中后三行的內(nèi)容和上述編碼配置的方式實(shí)現(xiàn)的效果是一樣的思灰。
1.4 運(yùn)行及結(jié)果
這里采用配置文件的方式來(lái)運(yùn)行玷犹,確保之前搭建的eureka-server、hello-service和feign-consumer項(xiàng)目都運(yùn)行起來(lái)洒疚,啟動(dòng)本項(xiàng)目歹颓,頁(yè)面輸入http://localhost:5555/hello,結(jié)果如下所示:
訪問(wèn)http://localhost:5555/hello會(huì)被自動(dòng)路由到http://localhost:8081/hello油湖,這樣就驗(yàn)證了路由轉(zhuǎn)發(fā)的成功巍扛。
2 面向服務(wù)的方式
顯而易見(jiàn)的是,傳統(tǒng)路由的配置方式比較繁瑣乏德,如果路由特別多的情況下撤奸,維護(hù)起來(lái)會(huì)很麻煩。為此喊括,可以將Gateway與Eureka整合起來(lái)胧瓜,這樣不用再寫(xiě)具體的url映射,url交給Eureka的服務(wù)發(fā)現(xiàn)機(jī)制去自動(dòng)維護(hù)郑什。
2.1 pom.xml
pom沿用上面的配置府喳,只需要再加入下面的Eureka依賴(lài)即可:
org.springframework.cloudspring-cloud-starter-netflix-eureka-client
2.2 application.properties
spring.application.name=api-gatewayserver.port=5555spring.cloud.gateway.discovery.locator.enabled=truespring.cloud.gateway.discovery.locator.lowerCaseServiceId=trueeureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/,http://peer3:1113/eureka/
其中spring.cloud.gateway.discovery.locator.enabled設(shè)置為true表示開(kāi)啟通過(guò)注冊(cè)中心進(jìn)行路由轉(zhuǎn)發(fā)的功能,spring.cloud.gateway.discovery.locator.lowerCaseServiceId設(shè)置為true表示通過(guò)小寫(xiě)形式來(lái)訪問(wèn)服務(wù)名稱(chēng)蘑拯。
2.3 運(yùn)行及結(jié)果
重啟本項(xiàng)目劫拢,頁(yè)面分別訪問(wèn)http://localhost:5555/feign-consumer/feign-consumer肉津、http://localhost:5555/feign-consumer/feign-consumer2和http://localhost:5555/feign-consumer/feign-consumer3,結(jié)果如下所示:
可以看到舱沧,和之前通過(guò)OpenFeign的消費(fèi)者訪問(wèn)的結(jié)果是一樣的,路由轉(zhuǎn)發(fā)是成功的偶洋。
3 Predicate和Filter
Predicate和Filter是Gateway中的核心熟吏,Predicate是選擇哪些請(qǐng)求需要處理,而Filter給選擇出來(lái)的請(qǐng)求做一些改動(dòng)玄窝,比如參數(shù)處理和安全校驗(yàn)等等牵寺。
3.1 Predicate
新建一個(gè)Spring Boot項(xiàng)目,命名為test-gateway恩脂,pom文件依賴(lài)和上述第1.1節(jié)中的pom依賴(lài)一致帽氓。這里我們用Postman來(lái)查看運(yùn)行結(jié)果。
3.1.1 時(shí)間匹配
spring.application.name=gateway-testserver.port=5556spring.cloud.gateway.routes[0].id=route_testspring.cloud.gateway.routes[0].uri=https://www.baidu.com/spring.cloud.gateway.routes[0].predicates[0]=After=2019-08-12T12:00:00+08:00[Asia/Shanghai]
上述After表示在2019年8月12日12點(diǎn)之后的請(qǐng)求可以被路由俩块,而B(niǎo)efore代表在指定時(shí)間之前可以被路由黎休,Between則代表在指定的時(shí)間區(qū)隔之內(nèi)可以被路由:
After=2019-08-12T12:00:00+08:00[Asia/Shanghai]Before=2019-08-12T12:00:00+08:00[Asia/Shanghai]Between=2019-08-12T12:00:00+08:00[Asia/Shanghai],2019-08-13T12:00:00+08:00[Asia/Shanghai]
3.1.2 請(qǐng)求方式匹配
spring.application.name=gateway-testserver.port=5556spring.cloud.gateway.routes[0].id=route_testspring.cloud.gateway.routes[0].uri=https://www.baidu.com/spring.cloud.gateway.routes[0].predicates[0]=Method=GET
上述表示只有GET請(qǐng)求才能被成功路由,訪問(wèn)Postman得到如下結(jié)果:
狀態(tài)碼為200玉凯,說(shuō)明成功訪問(wèn)势腮,這時(shí)我們改成POST請(qǐng)求,再來(lái)訪問(wèn):
狀態(tài)碼為404漫仆,說(shuō)明訪問(wèn)失敗捎拯。
3.1.3 請(qǐng)求路徑匹配
spring.application.name=gateway-testserver.port=5556spring.cloud.gateway.routes[0].id=route_testspring.cloud.gateway.routes[0].uri=https://www.baidu.com/spring.cloud.gateway.routes[0].predicates[0]=Path=/foo/{segment}
由上配置了匹配的請(qǐng)求路徑,Postman訪問(wèn)http://localhost:5556/foo/1盲厌,訪問(wèn)成功:
訪問(wèn)http://localhost:5556/foo/1/2署照,訪問(wèn)失敗:
3.1.4 請(qǐng)求參數(shù)匹配
spring.application.name=gateway-testserver.port=5556spring.cloud.gateway.routes[0].id=route_testspring.cloud.gateway.routes[0].uri=https://www.baidu.com/spring.cloud.gateway.routes[0].predicates[0]=Query=p1
上述配置了請(qǐng)求參數(shù)中必須含有p1參數(shù)才能路由成功吗浩,Postman訪問(wèn)http://localhost:5556/?p1=1建芙,路由成功:
訪問(wèn)http://localhost:5556/?p2=2,路由失斖孛取:
Query的值還可以使用正則表達(dá)式來(lái)進(jìn)行匹配岁钓,如下面的例子:
spring.application.name=gateway-testserver.port=5556spring.cloud.gateway.routes[0].id=route_testspring.cloud.gateway.routes[0].uri=https://www.baidu.com/spring.cloud.gateway.routes[0].predicates[0]=Query=p1,1.
上面配置了參數(shù)中的鍵必須含有p1,同時(shí)它所對(duì)應(yīng)的值是以1開(kāi)頭的兩個(gè)字符微王,Postman訪問(wèn)http://localhost:5556/?p1=1s屡限,路由成功:
Postman訪問(wèn)http://localhost:5556/?p1=1,路由失斂惶取:
3.2 Filter
這里只演示AddRequestParameter的用法钧大,更多的用法詳見(jiàn)Spring官網(wǎng)。
AddRequestParameter是在請(qǐng)求的路徑中添加相應(yīng)的參數(shù)罩旋,我們繼續(xù)使用上述的api-gateway項(xiàng)目啊央。
3.2.1 hello-service
首先需要對(duì)之前的hello-service項(xiàng)目做些更改眶诈,在其中的HelloController中添加一個(gè)foo方法如下所示:
@RequestMapping("/foo")publicStringfoo(Stringfoo) {returnfoo;? ? }
3.2.2 feign-consumer
然后在feign-consumer項(xiàng)目中的ConsumerController中添加下面的方法:
@RequestMapping("/foo")publicStringfoo(Stringfoo) {returnhelloService.foo(foo);? ? }
在IHelloService中添加下面的方法:
@RequestMapping("/foo")Stringfoo(@RequestParam("foo")Stringfoo);
在相應(yīng)的HelloServiceImplFallback降級(jí)類(lèi)中填入下面的降級(jí)方法:
@OverridepublicStringfoo(Stringfoo) {return"訪問(wèn)超時(shí),請(qǐng)重新再試瓜饥!";? ? }
3.2.3 application.properties
api-gateway網(wǎng)關(guān)的配置文件需要做些修改:
spring.application.name=api-gatewayserver.port=5555spring.cloud.gateway.discovery.locator.enabled=truespring.cloud.gateway.discovery.locator.lower-case-service-id=truespring.cloud.gateway.routes[0].id=add_request_parameter_routespring.cloud.gateway.routes[0].uri=lb://hello-servicespring.cloud.gateway.routes[0].predicates[0]=Method=GETspring.cloud.gateway.routes[0].filters[0]=AddRequestParameter=foo, bareureka.client.service-url.defaultZone=http://peer2:1112/eureka/,http://peer3:1113/eureka/
其中逝撬,uri表示配置路由轉(zhuǎn)發(fā)到hello-service的服務(wù)提供者。filters表示給匹配的請(qǐng)求中添加了一個(gè)foo=bar的參數(shù)乓土。需要注意的是宪潮,filters必須和predicates聯(lián)用,否則項(xiàng)目啟動(dòng)會(huì)失敗趣苏。
3.2.4 運(yùn)行及結(jié)果
隨后分別啟動(dòng)eureka-server狡相、hello-service和feign-consumer項(xiàng)目,然后啟動(dòng)api-gateway網(wǎng)關(guān)項(xiàng)目食磕,首先頁(yè)面訪問(wèn)http://localhost:9001/foo尽棕,以O(shè)penFeign消費(fèi)者的方式來(lái)訪問(wèn)服務(wù):
由上可以看到,當(dāng)沒(méi)有使用網(wǎng)關(guān)來(lái)訪問(wèn)服務(wù)的時(shí)候彬伦,頁(yè)面上沒(méi)有結(jié)果滔悉,也就是說(shuō)服務(wù)提供者沒(méi)有接收到foo參數(shù)。然后我們?cè)L問(wèn)http://localhost:5555/foo媚朦,以網(wǎng)關(guān)的方式來(lái)訪問(wèn)服務(wù):
以上可知氧敢,頁(yè)面上顯示了bar,foo參數(shù)被成功接收询张,在請(qǐng)求中會(huì)添加一個(gè)foo=bar的參數(shù)孙乖。
參考:http://blog.didispace.com/springcloud2/https://blog.csdn.net/weixin_30342639/article/details/99303710
https://mp.weixin.qq.com/s/WAQkqRAYo50ddRp5CbGuvw