網(wǎng)關(guān)是介于客戶端和服務(wù)器端之間的中間層,所有的外部請求都會先經(jīng)過網(wǎng)關(guān)這一層表箭。
也就是說,API 的實現(xiàn)方面更多的考慮業(yè)務(wù)邏輯序目,而安全猿涨、性能姆怪、監(jiān)控可以交由網(wǎng)關(guān)來做澡绩,這樣既提高業(yè)務(wù)靈活性又不缺安全性肥卡,典型的架構(gòu)圖如圖所示:
優(yōu)點如下:
(1)安全 步鉴,只有網(wǎng)關(guān)系統(tǒng)對外進行暴露璃哟,微服務(wù)可以隱藏在內(nèi)網(wǎng),通過防火墻保護阳似。
(2)易于監(jiān)控撮奏〉毖纾可以在網(wǎng)關(guān)收集監(jiān)控數(shù)據(jù)并將其推送到外部系統(tǒng)進行分析。
(3)易于統(tǒng)一認(rèn)證授權(quán)定拟∏嘧裕可以在網(wǎng)關(guān)上進行認(rèn)證驱证,然后再將請求轉(zhuǎn)發(fā)到后端的微服務(wù),而無須在每個微服務(wù)中進行認(rèn)證逆瑞。
(4)減少了客戶端與各個微服務(wù)之間的交互次數(shù)伙单。
總結(jié):微服務(wù)網(wǎng)關(guān)就是一個系統(tǒng)吻育,通過暴露該微服務(wù)網(wǎng)關(guān)系統(tǒng),方便我們進行相關(guān)的鑒權(quán)摊趾,安全控制,日志統(tǒng)一處理砾层,易于監(jiān)控的相關(guān)功能肛炮。
1.網(wǎng)關(guān)微服務(wù)搭建
(1)pom.xml添加坐標(biāo)
<dependency>
????<groupId>org.springframework.cloud</groupId>
????<artifactId>spring‐cloud‐starter‐gateway</artifactId>
</dependency>
<dependency>
????<groupId>org.springframework.cloud</groupId>
????<artifactId>spring‐cloud‐starter‐netflix‐hystrix</artifactId>
</dependency>
<dependency>
????<groupId>org.springframework.cloud</groupId>
????<artifactId>spring‐cloud‐starter‐netflix‐eureka‐client</artifactId>
</dependency>
(2)創(chuàng)建引導(dǎo)類
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
????public static void main(String[] args) {
????????SpringApplication.run(GatewayApplication.class, args);
????}
}
(3)在resources下創(chuàng)建application.yml
spring:
????application:
????????name: sysgateway
????cloud:
????????gateway:
????????????routes:
????????????‐ id: goods
????????????????uri: lb://goods
???????????????? predicates:
???????????????? ‐ Path=/goods/**
???????????????? filters:
???????????????? ‐ StripPrefix= 1
????????????‐ id: system
????????????????uri: lb://system
???????????????? predicates:
???????????????? ‐ Path=/system/**
???????????????? filters:
???????????????? ‐ StripPrefix= 1
server:
????port: 9101
eureka:
????client:
????????service‐url:
????????????defaultZone: http://127.0.0.1:6868/eureka
????????instance:
????????????prefer‐ip‐address: true
2.微服務(wù)網(wǎng)關(guān)跨域
修改application.yml ,在spring.cloud.gateway節(jié)點下添加配置:
????????globalcors:
????????????cors‐configurations:
????????????????'[/**]': # 匹配所有請求
????????????????????allowedOrigins: "*" #跨域處理 允許所有的域
???????????????????? allowedMethods: # 支持的方法
???????????????????? ‐ GET
???????????????????? ‐ POST
???????????????????? ‐ PUT
???????????????????? ‐ DELETE
3.微服務(wù)網(wǎng)關(guān)過濾器
可以通過網(wǎng)關(guān)過濾器實現(xiàn)一些邏輯處理祟印,比如IP黑白名單攔截、如下為兩個設(shè)定先后順序的過濾器:
(1)IpFilter
@Component
public class IpFilter implements GlobalFilter, Ordered {
????@Override
????public Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain) {
????????System.out.println("經(jīng)過第1個過濾器IpFilter");
???????? ServerHttpRequest request = exchange.getRequest();
???????? InetSocketAddress remoteAddress = request.getRemoteAddress();
???????? System.out.println("ip:"+remoteAddress.getHostName());
???????? return chain.filter(exchange);
????}
????@Override
????public int getOrder() {
????????return 1;
????}
}
(2)UrlFilter
@Component
public class UrlFilter implements GlobalFilter, Ordered {
????@Override
????public Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain) {
????????System.out.println("經(jīng)過第2個過濾器UrlFilter");
???????? ServerHttpRequest request = exchange.getRequest();
???????? String url = request.getURI().getPath();
???????? System.out.println("url:"+url);
???????? return chain.filter(exchange);
????}
????@Override
????public int getOrder() {
????????return 2;
????}
}
4.網(wǎng)關(guān)限流
(請求通過網(wǎng)關(guān)系統(tǒng)后才能路由到微服務(wù)中)
需求:每個ip地址1秒內(nèi)只能發(fā)送1次請求悲幅,多出來的請求返回429錯誤汰具。
(1)spring cloud gateway 默認(rèn)使用redis的RateLimter限流算法來實現(xiàn)菱魔。
我們要使用首先需要引入redis的依賴
<!‐‐redis‐‐>
<dependency>
????<groupId>org.springframework.boot</groupId>
????<artifactId>spring‐boot‐starter‐data‐redis‐reactive</artifactId>
????<version>2.1.3.RELEASE</version>
</dependency>
(2)定義KeyResolver
在GatewayApplicatioin引導(dǎo)類中添加如下代碼澜倦,KeyResolver用于計算某一個類型的限流的KEY也就是說,可以通過KeyResolver來指定限流的Key碘勉。
//定義一個KeyResolver
@Bean
public KeyResolver ipKeyResolver() {
????return new KeyResolver() {
????????@Override
????????public Mono<String> resolve(ServerWebExchange exchange) {
????????????return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
????????????}
????????};
}
(3)修改application.yml中配置項验靡,指定限制流量的配置以及REDIS的配置
修改后最終配置如下:
spring:
????application:
????????name: sysgateway
????cloud:
????????gateway:
????????????globalcors:
????????????????cors‐configurations:
????????????????????'[/**]': # 匹配所有請求
???????????????????? allowedOrigins: "*" #跨域處理 允許所有的域
???????????????????? allowedMethods: # 支持的方法
???????????????????? ‐ GET
???????????????????? ‐ POST
???????????????????? ‐ PUT
???????????????????? ‐ DELETE
????????????routes:
????????????‐ id: goods
????????????????uri: lb://goods
???????????????? predicates:
???????????????? ‐ Path=/goods/**
???????????????? filters:
???????????????? ‐ StripPrefix= 1
???????????????? ‐ name: RequestRateLimiter #請求數(shù)限流 名字不能隨便寫
????????????????????args:
????????????????????????key‐resolver: "#{@ipKeyResolver}"
???????????????????????? redis‐rate‐limiter.replenishRate: 1 #令牌桶每秒填充平均速率
???????????????????????? redis‐rate‐limiter.burstCapacity: 1 #令牌桶總?cè)萘?/p>
????????????‐ id: system
????????????????uri: lb://system
???????????????? predicates:
???????????????? ‐ Path=/system/**
???????????????? filters:
????????????????‐ StripPrefix= 1
????# 配置Redis 127.0.0.1可以省略配置
????redis:
????????host: 192.168.200.128
????????port: 6379
????server:
????????port: 9101
????eureka:
????????client:
????????service‐url:
????????????defaultZone: http://127.0.0.1:6868/eureka
????instance:
????????prefer‐ip‐address: true
解釋:
burstCapacity:令牌桶總?cè)萘俊?/p>
replenishRate:令牌桶每秒填充平均速率胜嗓。
key-resolver:用于限流的鍵的解析器的 Bean 對象的名字辞州。它使用 SpEL 表達式根據(jù)#{@beanName}從 Spring 容器中獲取 Bean 對象件蚕。通過在 replenishRate 和中設(shè)置相同的值來實現(xiàn)穩(wěn)定的速率 burstCapacity 产禾。設(shè)置 burstCapacity 高于時亚情,可以允許臨時突發(fā) replenishRate 哈雏。在這種情況下,需要在突發(fā)之間允許速率限制器一段時間(根據(jù) replenishRate )土浸,因為2次連續(xù)突發(fā)將導(dǎo)致請求被丟棄( HTTP 429 ‐ Too Many Requests )
key-resolver: "#{@userKeyResolver}" 用于通過SPEL表達式來指定使用哪一個KeyResolver.
如上配置:
表示 一秒內(nèi)彭羹,允許 一個請求通過,令牌桶的填充速率也是一秒鐘添加一個令牌还最。
最大突發(fā)狀況也只允許 一秒內(nèi)有一次請求毡惜,可以根據(jù)業(yè)務(wù)來調(diào)整 经伙。
(4)測試
1.啟動redis帕膜;2.啟動注冊中心;3.啟動商品微服務(wù)作瞄;4.啟動gateway網(wǎng)關(guān)危纫;5;打開瀏覽器 http://localhost:9101/goods/brand
6.快速刷新契耿,當(dāng)1秒內(nèi)發(fā)送多次請求螃征,就會返回429錯誤。
????????????????