Spring Cloud Gateway入门学习
文章目录
Spring Cloud Gateway是Spring Cloud的一个项目,它是基于Spring,Webflux,Spring boot等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式,目标为替换Netflix Zuul项目,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/指标和限流。
Spring Cloud Gateway的主要特征:
- 基于Spring Framework 5,SpringBoot2.0
- 动态路由
- Predicates和Filters作用于特定路由
- 集成Hystrix断路器
- 集成SpringCloud DiscoveryClient
- 易于编写的Predicates和Filters
- 限流
- 路径重写
基本概念:
Route(路由):这是网关的基本构建块。它由一个ID,一个目标uri,一组断言和一组过滤器定义。如果断言成功,则路由匹配。
Predicate(断言):这是一个java8的Predicate。输入类型是一个ServerWebExchange。我们可以使用它来匹配来自HTTP请求的任何内容,例如headers或参数。
Filter(过滤器):我们可以使用 它来修改请求和参数。
一,基本使用
1.1 引用依赖
springboot版本2.4.5,springcloud版本2020.0
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.0.1</version>
</dependency>
1.2 启动类
package com.lmc.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author lmc
* @Description: TODO
* @Create 2021-10-13 23:08
* @version: 1.0
*/
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication5010 {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication5010.class, args);
}
}
1.3 配置文件
server:
port: 5010
spring:
application:
name: tools-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # #开启根据注册中心路由,并随服务的改变而改变路由
lower-case-service-id: true # #开启服务名转为小写
routes:
- id: tools-task
uri: lb://tools-task
predicates:
- Path=/tltk
filters:
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
spring.cloud.gateway.routes.id:自定义的路由ID,保持唯一
spring.cloud.gateway.routes.id.uri:目标服务地址
spring.cloud.gateway.routes.id.uri: lb//XXXX(服务名):配置服务
spring.cloud.gateway.routes.id.predicates:路由条件,predicates接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方式来将predicate组合成其他复杂的逻辑
spring.cloud.gateway.routes.id.filters StripPrefix=n:去掉n个路径
spring.cloud.gateway.discovery.locator.enabled:是否根据注册中心路由,随服务的改变而改变路由
spring.cloud.gateway.discovery.locator.lower-case-service-id:是否强制将服务名转为小写
1.4 测试
现服务tools-task接口: http://localhost:8083/test/api
先启动服务注册中心,再启动gateway,再启动tools-task,访问: http://localhost:5010/tools-task/test/api,成功访问数据
二, 过滤器
在Spring Cloud Gateway中,过滤器的作用主要是为对请求与返回进行处理,可以简单理解为一个方法的前置事件与后置事件,所以一般过滤器被分为两种,分别为“pre”和“post”。在“pre”类型的过滤器可以做参数校验,权限校验,流量监控,日志输出,协议转换等,在“post”类型的过滤器中可以做响应内容,响应头的修改,日志输出,流量监控等。
过滤器执行过程中,order越大,优先级越低
2.1 常用过滤器
- AddRequestHeader:为请求增加一个header
- AddRequestParameter:为请求新增请求参数
- AddResponseHeader:为响应新增返回header
- DedupeResponseHeader:为去除返回信息中重复的header信息
- ……
2.2 自定义过滤器
自定义过滤器,需要实现GatewayFilter和Ordered接口
举例: 请求完成时间过滤器
package com.lmc.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 计算请求完成时间过滤器
* @author sw
*
*/
public class ElapsedFilter implements GatewayFilter, Ordered {
/**
* 过滤器存在优先级,order越大,优先级越低
*/
@Override
public int getOrder() {
// TODO Auto-generated method stub
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put("beginTime", System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute("beginTime");
if (startTime != null) {
System.out.println(exchange.getRequest().getURI().getRawPath() + " : " + (System.currentTimeMillis() - startTime) + "ms");
}
})
);
}
}
然后将该过滤器绑定到路由中:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/lmchh/**")
.filters(f -> f.stripPrefix(1)
.filter(new ElapsedFilter()))
.uri("http://localhost:5020")
.order(0))
.build();
}
2.3 全局过滤器
当需要所有请求都要经过某些操作时,可以使用全局过滤器。全局过滤器需要实现GlobalFilter接口
package com.lmc.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 全局过滤器
* 所有请求都会执行
* @author sw
*
*/
@Component
public class GlobalFilter implements org.springframework.cloud.gateway.filter.GlobalFilter, Ordered {
@Override
public int getOrder() {
// TODO Auto-generated method stub
return -10;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("this is global filter ... start ...");
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
System.out.println("this is global filter ... end ...");
})
);
}
}
三, Gateway功能
3.1 认证
举例,认证过滤器:
package com.lmc.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
/**
* 对客户端header中的Authorization信息进行简单认证
* @author sw
*
*/
@Component
public class TokenAuthenticationFilter extends AbstractGatewayFilterFactory {
private static final String Bearer_ = "Bearer ";
@Override
public GatewayFilter apply(Object config) {
// TODO Auto-generated method stub
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpRequest.Builder mutate = request.mutate();
ServerHttpResponse response = exchange.getResponse();
try {
//获取header中的Authorization
String header = request.getHeaders().getFirst("Authorization");
if (header == null || !header.startsWith(Bearer_)) {
throw new RuntimeException("请求头中Authorization的信息为空");
}
//截取Authorization Bearer
String token = header.substring(7);
//可把token存到redis中,此时直接在redis中判断是否由此key,有则校验通过,否则校验失败
if(!StringUtils.isEmpty(token)) {
System.out.println("校验通过");
//有token,把token设置到header中,传递给后端服务
mutate.header("userDetails", token).build();
}else {
//token无效
System.out.println("token无效");
return null;
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
ServerHttpRequest build = mutate.build();
return chain.filter((ServerWebExchange) exchange.mutate().request(build));
};
}
}
配置:
filters:
- StripPrefix=1
# 进行token认证
- TokenAuthenticationFilter
3.2 熔断
熔断降级:在分布式系统中,网关作为流量的入口,大量请求进入网关,向后端远程系统或服务发起调用,后端服务不可避免的会产生调用失败(超时或者异常),失败时不能让请求堆积在网关上,需要快速失败并返回回去,这就需要在网关上做熔断,降级操作。
所需依赖:
<!-- 熔断,降级 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
配置:
filters:
- StripPrefix=1
## 熔断降级配置
- name: Hystrix
args:
name: defaultfallback
fallbackUri: 'forward:/defaultfallback'
举例,熔断回调:
package com.lmc.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
@RestController
public class DefaultHystrixController {
@RequestMapping("/defaultfallback")
@HystrixCommand(commandProperties= {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public Map<String, Object> defaultfallback() {
System.out.println("默认降级操作...");
Map<String, Object> map = new HashMap<String, Object>();
map.put("resultCode", "fail");
map.put("resultMessage", "服务异常...");
map.put("returnObj", null);
return map;
}
}
创建接口测试:
设置3秒内没响应就进行熔断降级
@RequestMapping("/timeout")
public String timeout() {
try {
Thread.sleep(5000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return "timeout";
}
设置/timeout映射睡眠5秒,引发熔断机制。
访问 /timeout ,结果调用了/defaultfallback。
3.3 限流
限流:网关上有大量请求,对指定服务进行限流,可以很大程度上提高服务的可用性与稳定性,限流的目的是通过对并发访问/请求进行限速,或对一个时间窗口内的请求进行限速来保护系统。一旦达到限制速率则可以拒绝服务,排队或等待,降级。
集成限流:Spring Cloud Gateway默认集成了Redis限流,可以对不同服务做不同维度的限流,如:IP限流,用户限流,接口限流。(需提前开启Redis)
举例,新建限流配置类,通过KeyResolver来指定限流的key
package com.lmc.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
/**
* 路由限流配置
* @author sw
*
*/
@Configuration
public class RateLimiterConfig {
@Bean(value = "remoteAddrKeyResolver")
public KeyResolver remoteAddrKeyResolver() {
//IP限流
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
//接口限流
// return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
限流方式:
- IP限流
- 接口限流
- 用户限流
配置类
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启根据注册中心路由,并随服务的改变而改变路由
lower-case-service-id: true #开启服务名转为小写
routes:
- id: provider
uri: lb://api-eureka-provider
predicates:
- Path=/provider/**
filters:
- StripPrefix=1
# 进行token认证
#- TokenAuthenticationFilter
## 熔断降级配置
- name: Hystrix
args:
name: defaultfallback
fallbackUri: 'forward:/defaultfallback'
- name: RequestRateLimiter
args:
# 使用SpEL名称引用Bean,与上面新建的RateLimiterConfig类中的bean的name相同
key-resolver: '#{@remoteAddrKeyResolver}'
# 每秒最大访问次数
redis-rate-limiter.replenishRate: 2
# 令牌桶最大容量
redis-rate-limiter.burstCapacity: 2
注意:
filter名称必须是RequestRateLimiter,
redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求
redis-rete-limiter.burstCapacity:令牌桶的容量,允许在一秒内完成的最大请求数。
key-resolver:使用SpEL按名称引用bean
3.4 动态路由
动态路由的内容较多,今天做笔记已经做到十一点半,下篇再讲好了。
…
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/81617.html