赞
踩
它不能在传统的servlet容器中工作,也不能构建war包
路由是网关中最基础的部分,路由信息包括一个ID,一个目的URL、一组断言工厂、一组Filter组成,如果断言为真,则说明请求的URL和配置的路由匹配
Java8中的断言函数,SpringCloud Gateway中的断言函数类型就是Spring5 框架中的ServerWebExchange.断言函数允许开发者去定义匹配Http request中的任何信息,比如请求头和参数等,
SpringCloud Gateway中的filter分为Gateway Filter和Global Filter,Filter可以对请求和响应进行处理。
1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2、application.yml
server:
port: 8889
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: order_route #路由的唯一标识,路由到order
uri: http://localhost:8004 # 需要转发的地址
# 断言规则 用于路由规则的匹配
predicates:
- Path=/order-server/**
# 转发之前去掉第一层路径
filters:
- StripPrefix=1
浏览器进行访问http://localhost:8889/order-server/order/orderList
即可转发到你的http://localhost:8004/order/orderList
增加一个依赖
<!--nacos依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
修改yml文件
server:
port: 8889
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: order_route
uri: lb://order-server #lb表示使用nacos本地的负载均衡策略
predicates:
- Path=/order-server/**
filters:
- StripPrefix=1
#配置nacos
nacos:
discovery:
server-addr: 127.0.0.1:8847
username: nacos
password: nacos
技巧:断言和过滤路由简写方式
yml编写方式
server:
port: 8889
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 120.0.0.1:8847
username: nacos
password: nacos
gateway:
discovery:
locator:
enabled: true #自动识别nacos上的服务
运行即可,发现我们服务可以正常访问。
官网地址:
此类型断言根据时间做判断,主要由三个:
AfterRoutePredicateFactory
:接受一个日期参数,判断请求日期是否晚于指定日期
BeforeRoutePredicateFactory
:接受一个日期参数,判断请求日期是否早于指定日期
BetweenRoutePredicateFactory
:接受一个日期参数,判断请求日期是否在指定时间段内
案例一(晚于指定日期)
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
案例二(早于指定日期)
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
案例三(指定日期之间)
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
RemoteAddrRoutePredicateFactory
: 接收一个ip地址段,判断请求主机是否在地址端中
- RemoteAddr=192.168.1.1/24
CookieRoutePredicateFactory
: 接收两个参数,cookie名字和一个正则表达式,判断请求cookie是否具有给定名称且与正则表达式匹配。
- Cookie=chocolate, ch.p
HeaderRoutePredicateFactory
: 接收两个参数,标题名称和一个正则表达式,判断请求Header是否具有给定名称且与正则表达式匹配。
- Header=X-Request-Id, \d+
HostRoutePredicateFactory
: 接收一个参数,主机名模式。判断请求的Host是否匹配规则
- Host=**.somehost.org,**.anotherhost.org
MethodRoutePredicateFactory
: 接收一个参数,判断请求类型是否跟指定的类型匹配
- Method=GET,POST
{segment}:需要携带参数
- Path=/red/{segment},/blue/{segment}
例: /red/1
or /red/aaa
or /blue/red
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
- Query=green
例入: ?green=121
- Query=red, gree.
例入:?red=gree
,值需要匹配后面的正则
自定义断言工厂需要继承AbstractRoutePredicateFactory
类,重写apply方法的逻辑,在apply方法中可以通过exchange.getRequest()拿到ServerHttpRequest对象,从而可以获取到请求的参数、请求方式、请求头等信息
要求:
RoutePredicateFactory
作为结尾AbstractRoutePredicateFactory
shortcutFieldOrder
来进行绑定@Component
public class CheckNameRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckNameRoutePredicateFactory.Config> {
public CheckNameRoutePredicateFactory() {
super(CheckNameRoutePredicateFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("name");
}
@Override
public Predicate<ServerWebExchange> apply(CheckNameRoutePredicateFactory.Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
return "YangLi".equals(config.getName());
}
};
}
/**
* 用于接受配置文件中 断言的信息
*/
@Validated
public static class Config {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
yml文件加上
- CheckName=YangLi
测试即可。
由于内置过滤器工厂太多,我这里随便列几个,想看全部内置过滤器工厂,可去官网查看
- AddRequestHeader=X-Request-red, red
进行测试
@RequestMapping("/header")
public String header(@RequestHeader("X-Request-red") String color){
return color;
}
结果:
成功返回red
- AddRequestParameter=color, blue
进行测试
@RequestMapping("/parameter")
public String parameter(@RequestParam("color") String color){
return color;
}
结果:
成功返回blue
- PrefixPath=/mall-order #前缀,对应微服务需要配置context-path
mall-order中需要配置
server:
servlet:
context-path: /mall-order
- RedirectTo=302, https://www.baidu.com/ #重定向到百度
AbstractGatewayFilterFactory
例子:请求后面的参数name=YangLi才可以
- CheckAuth=YangLi #自定义拦截器,必须?name=YangLi
@Component
public class
CheckAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> {
public CheckAuthGatewayFilterFactory() {
super(CheckAuthGatewayFilterFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("value");
}
@Override
public GatewayFilter apply(CheckAuthGatewayFilterFactory.Config config) {
return (exchange, chain) -> {
String name = exchange.getRequest().getQueryParams().getFirst("name");
if (StringUtils.isNotBlank(name)){
if (config.getValue().equals(name)){
return chain.filter(exchange);
}else{
// 返回404
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return exchange.getResponse().setComplete();
}
}
return chain.filter(exchange);
};
}
/**
* 用于接受配置文件中 过滤器的信息
*/
@Validated
public static class Config {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
局部过滤器和全局过滤器的区别?
局部:局部针对某个路由,需要在路由中进行配置
全局:针对所有路由请求,一旦定义就会全局使用
只需要实现GlobalFilter
接口即可
@Component
public class LogGlobalFilter implements GlobalFilter {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
logger.info(exchange.getRequest().getPath().value());
return chain.filter(exchange);
}
}
要启用Reactor Netty访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true
它是java系统属性,不是Spring Boot属性
进行访问,结果会打印日志信息
2022-07-01 15:32:12.140 INFO 15400 --- [ctor-http-nio-2] reactor.netty.http.server.AccessLog : 0:0:0:0:0:0:0:1 - - [01/Jul/2022:15:32:11 +0800] "GET /order-server/order/parameter HTTP/1.1" 200 4 8889 942 ms
前后端分离需要跨域,所以我们直接在网关这里进行配置
yml方式配置:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': # 允许访问的资源
allowedOrigins: "*" #跨域允许来源
allowedMethods:
- GET
- POST
配置类的方式
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许的请求头参数
corsConfiguration.addAllowedHeader("*");
// 允许的method
corsConfiguration.addAllowedMethod("*");
// 允许的来源
corsConfiguration.addAllowedOrigin("*");
// 允许访问的资源
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
网关作为内部系统外的一层屏障,对内起到一定的保护作用,限流便是其中之一,网关层的限流可以简单的针对不同路由进行限流,也可针对业务的接口进行限流,或者根据接口的特征分组限流。
1、添加依赖
<!--sentinel整合gateway的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!--sentinel的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、添加配置
sentinel:
transport:
dashboard: 127.0.0.1:8010
3、运行并进入控制台:
测试简单流控规则(一秒钟访问两次将会被限流):
在浏览器进行访问并快速刷新,触发流控规则
名词解读:
针对请求属性
Client IP 根据客户端ip地址进行流控
Remote Host 根据远程域名进行流控
Header:根据请求头名字匹配对应值进行流控
URL参数和Cookie方式与上述雷同
新建api分组(针对API接口流控)
新增流控规则,选择刚刚新加的api分组
进行测试发现,针对这两个接口发生流控,其他接口无流控
降级规则
当然,相应api也可以配置降级规则
系统规则
这个与sentinel配置系统保护用法一致。
自定义流控异常返回信息
配置类方式:
@Configuration
public class GatewayConfig {
@PostConstruct
public void init(){
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
HashMap<String,String> map = new HashMap<>(10);
map.put("code", HttpStatus.TOO_MANY_REQUESTS.toString());
map.put("message","限流了");
// 自定义异常处理
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
yml方式
spring:
application:
name: api-gateway
cloud:
gateway:
scg:
fallback:
mode: response
response-body: '{"code":403,"mess":"限流了"}'
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。