功能:
Spring Cloud网关的目的是提供一种简单而有效的方法来路由到API,并向它们提供跨领域的关注,例如:安全性,监视/度量和弹性。
对比:
官方对比
工作原理:
客户端向Spring Cloud网关发出请求。
如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。
该处理程序运行通过特定于请求的筛选器链发送请求。
筛选器由虚线分隔的原因是,筛选器可以在发送代理请求之前或之后执行逻辑。执行所有“前置”过滤器逻辑,然后发出代理请求。
发出代理请求后,将执行“后”过滤器逻辑。
引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
配置文件
server:
port: 8711
spring:
application:
name: gateway-service
cloud:
gateway:
# discovery:
# locator:
# # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
# enabled: true
# 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
routes:
# 路由标识(id:标识,具有唯一性) 转发指定地址并传入参数
- id: CLIENT1-SERVICE
# 目标服务地址(uri:地址,请求转发后的地址)
uri: http://localhost:8702
# 路由条件(predicates:断言,匹配 HTTP 请求内容)
predicates:
## 匹配路径
- Path=/client1/get/**
# filters:
# - StripPrefix=1
# 过滤器(filters:过滤器,过滤规则)
eureka:
instance:
preferIpAddress: true
instance-id: gateway_service #注册中心右边的位置的显示
client:
serviceUrl:
defaultZone: http://localhost:8701/eureka
ps:其他断言可以参考官方文档www.springcloud.cc/spring-clou…
路由测试:
分别启动注册中心,client1和gateway
自定义过滤器
package org.example.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("进入自定义过滤器");
Object object;
String key = exchange.getRequest().getQueryParams().getFirst("id");
System.out.println("传入参数为:"+key);
if(!"123".equals(key)){
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
测试:
自定义路由断言工厂
package org.example.predicateFactory;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/**
* @author shock wave 2
* @version 1.0
* @description: TODO 自定义断言工厂需要继承AbstractRoutePredicateFactory重写apply方法
* @date 2021/6/30 15:48
*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
public MyRoutePredicateFactory() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new Predicate<ServerWebExchange>() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
String userName = serverWebExchange.getRequest().getQueryParams().getFirst("userName");
if(StringUtils.isBlank(userName)){
return false;
}
//检查请求参数中的userName是否与配置的数据相同,如果相同则允许访问,否则不允许访问
if(userName.equals(config.getName())){
return true;
}
return false;
}
};
}
/**
* @description: TODO 获取配置参数
*/
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("name");
}
@Data
public static class Config {
private String name;
}
}
yml文件修改
server:
port: 8711
spring:
application:
name: gateway-service
cloud:
gateway:
# discovery:
# locator:
# # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
# enabled: true
# 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
routes:
# 路由标识(id:标识,具有唯一性) 转发指定地址并传入参数
- id: CLIENT1-SERVICE
# 目标服务地址(uri:地址,请求转发后的地址)
uri: http://localhost:8702
# 路由条件(predicates:断言,匹配 HTTP 请求内容)
predicates:
## 匹配路径
- Path=/client1/**
#可以使用这两种方式
# - name: My
#前面为自定义路由断言工厂的前缀(注意:这个地方名字一定要命名正确。。。RoutePredicateFactory)
- My=shockwave
# filters:
# - StripPrefix=1
# 过滤器(filters:过滤器,过滤规则)
eureka:
instance:
preferIpAddress: true
instance-id: gateway_service #注册中心右边的位置的显示
client:
serviceUrl:
defaultZone: http://localhost:8701/eureka
测试
先随便来个参数
使用正常参数
自定义局部过滤器工厂
代码
package org.example.filter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/**
* @author shock wave 2
* @version 1.0
* @description: TODO
* @date 2021/6/30 17:10
*/
@Component
@Slf4j
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
//构造器是必须要的,去掉这个会报错,一般idea会提示加上这个,但是我的idea自定义过滤工厂的时候并没有红线提醒,需手动加上
public MyGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String version = exchange.getRequest().getQueryParams().getFirst("version");
if (!config.getVersion().equals(version)) {
log.info("参数错误");
}
return chain.filter(exchange);
};
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("version");
}
@Data
public static class Config {
private String version;
}
}
yml配置
server:
port: 8711
spring:
application:
name: gateway-service
cloud:
gateway:
# discovery:
# locator:
# # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
# enabled: true
# 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
routes:
# 路由标识(id:标识,具有唯一性) 转发指定地址并传入参数
- id: CLIENT1-SERVICE
# 目标服务地址(uri:地址,请求转发后的地址)
uri: http://localhost:8702
# 路由条件(predicates:断言,匹配 HTTP 请求内容)
predicates:
## 匹配路径
- Path=/client1/**
#可以使用这两种方式
# - name: My
#前面为自定义路由断言工厂的前缀(注意:这个地方名字一定要命名正确。。。RoutePredicateFactory)
- My=shockwave
filters:
- My=sr
# 过滤器(filters:过滤器,过滤规则)
eureka:
instance:
preferIpAddress: true
instance-id: gateway_service #注册中心右边的位置的显示
client:
serviceUrl:
defaultZone: http://localhost:8701/eureka
测试
结果