GateWay使用
一、概念及使用
文档地址:
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/
Gateway 配置:https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/appendix.html
作用:
名词概念
1、导入坐标
<!--nacos服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- sentinel服务降级熔断依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--gateWay网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- gateway网关整合sentinel进行限流降级 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
2、predicates断言
spring:
cloud:
#nacos服务注册发现
nacos:
discovery:
username: nacos
password: nacos
namespace: public
server-addr: 192.168.32.128:8848,192.168.32.129:8848
gateway:
routes:
- id: order-serve #路由id(随便写的唯一值最好是和服务名对应上 好区分)
order: 0 #order 越小,优先级越高
uri: lb://order-service #路由转发的nacos服务地址(lb://服务名称)
predicates:
- Path=/order_serve/** #以order_serve开头的请求转发到order-service服务上
- RemoteAddr=192.168.32.78
gateWay提供了11种 predicates
断言工厂
断言predicates 可以组合使用 匹配成功路由转发 否则返回404
名称 | 说明 | 示例 |
---|---|---|
After | 晚于指定日期时间的请求 | -After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 早于指定日期时间的请求 | -Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 介于指定日期时间内的请求 | -Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ 正则表达式 |
Host | 请求域名匹配 | - Host=**.baidu.com, **.ali.com 支持通配符 |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | Path=/order-server/{segment},/blue/** {segment}:占位符 |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 | Weight=组名称,权重值 Weight=group1,6 |
# 权重的配置规则
spring:
cloud:
gateway:
routes:
- id: order-service-high
uri: lb://order-service
predicates:
- Weight=group1, 8
- id: order-service-low
uri: lb://order-service
predicates:
- Weight=group1, 2
3、filter过滤器
spring:
cloud:
gateway:
routes:
- id: order-serve #路由id(随便写的唯一值最好是和服务名对应上 好区分)
order: 0 #order 越小,优先级越高
uri: lb://order-service #路由转发的nacos服务地址(lb://服务名称)
predicates:
- Path=/order_serve/** #以order_serve开头的请求转发到order-service服务上
- RemoteAddr=192.168.32.78
filters:
#过滤器StripPrefix,作用是去掉请求路径的最前面n个部分截取掉
#http://localhost/order_serve/name/bar/foo 会变成 http://localhost/order_serve/bar/foo
- StripPrefix=1 #转发之前去掉第一层路径order-serve htpp://localhost:8080/seata/addorder
- AddRequestHeader=token # 将token添加到所有匹配请求的header中
- RemoveRequestHeader=token #删除header token字段然后转发
- PrefixPath=/my_path # 将/mypath作为所有匹配请求的路径的前缀。因此,对 /order_serve 的请求将发送到 /mypath/order_serve/
- AddResponseHeader=X-Response-Foo, Bar # 将X-Response-Foo:BarHeaders 添加到所有匹配请求的下游响应的 Headers 中
- RemoveResponseHeader=X-Response-Foo # 这将从响应中删除 Response Headers 中的 X-Response-Foo,然后将其返回给网关 Client 端
- AddRequestParameter=host, 127.0.0.1 # 将 host=127.0.0.1 添加到所有匹配请求的 Param 参数中
- RemoveRequestParameter=red # 将 red 参数发送到下游之前将其删除
- SetPath=/{segment} # 请求路径/red/blue 设置为 /blue 发送到下游请求
- SetRequestHeader=X-Request-Red, Blue # 注意:替换(而不是添加),替换 Request Header 的 X-Request-Red=Blue
- SetResponseHeader=X-Response-Red, Blue # 注意:替换(而不是添加),替换 Response Header 的 X-Response-Red=Blue
- RewritePath=/order_serve/(?<segment>.*),/$\{segment} #http:://localhost/order_serve/foo 变成 http:://localhost/foo
自定义过滤器
@Component
@Slf4j
public class AppCheckAuthGatewayFilter implements GlobalFilter, Ordered {
/**
* 参考 GlobalFilter接口的实现类
*
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("---------执行全局过滤器-----------");
// 请求头或者请求参数中获取token
String token = exchange.getRequest().getHeaders().getFirst("token");
//String token = exchange.getRequest().getQueryParams().getFirst("token");
if (StringUtils.isBlank(token)) {
log.info("token is null");
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
// 401 用户没有访问权限
response.setStatusCode(HttpStatus.UNAUTHORIZED);
byte[] bytes = HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes();
DataBuffer buffer = response.bufferFactory().wrap(bytes);
// 请求结束,不继续向下请求
return response.writeWith(Mono.just(buffer));
}
// TODO 校验token进行身份认证
log.info("开始校验token,token={}", token);
return chain.filter(exchange);
}
/**
* 当有多个过滤器时, order值越小,越优先先执行
*
* @return
*/
@Override
public int getOrder() {
return 100;
}
}
4、路由元数据
通过 metadata为每个路由设置额外参数
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/order-serve/**
metadata:
- key1=value1
- key2=value2
5、CORS跨域配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: 127.0.0.1:21000
allowedMethods:
- POST
- GET
二、gateWay整合Sentinel熔断降级处理
1、流控降级配置
spring:
cloud:
gateway:
routes:
- id: order-serve #路由id(随便写的唯一值最好是和服务名对应上 好区分)
order: 0 #order 越小,优先级越高
uri: lb://order-service #路由转发的nacos服务地址(lb://服务名称)
predicates:
- Path=/order_serve/** #以order_serve开头的请求转发到order-service服务上
- RemoteAddr=192.168.32.78
filters:
- AddRequestHeader=token # 将token添加到所有匹配请求的header中
##注册发现中心
nacos:
discovery:
username: nacos
password: nacos
namespace: public
server-addr: 192.168.32.128:8848,192.168.32.129:8848
#配置sentinel
sentinel:
transport:
dashboard: 192.168.32.132:8858
client-ip: 192.168.32.1
port: 8719
web-context-unify: false
#
scg:
fallback:
mode: response
response-status: 426
response-body: "{'code':426,'message':'Too many requests'}"
2、配置流控降级异常处理
yml配置
spring:
cloud:
sentinel:
scg:
fallback:
content-type: application/json
response-status: 429
response-body: "{'code':426,'message':'Too many requests'}"
mode: response
gateway 配置项
参数 | 说明 |
---|---|
mode | 流控处理逻辑 (选择 redirect or response) 重定向还是返回response |
redirect | 响应模式为 ‘redirect’ 重定向模式对应的重定向 URL |
response-body | 响应模式为 ‘response’ 模式对应的响应内容 |
response-status | 响应的状态码 |
content-type | 响应模式为 ‘response’ 模式对应的 content-type |
3、自定义异常处理
@Configuration
public class DiyBlockRequestHandler implements BlockRequestHandler {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable e) {
String msg = null;
if (e instanceof FlowException) {
msg = "限流了,请稍后访问";
} else if (e instanceof DegradeException) {
msg = "降级了,返回默认数据";
} else if (e instanceof ParamFlowException) {
msg = "热点参数限流";
} else if (e instanceof SystemBlockException) {
msg = "系统规则(负载/...不满足要求)";
} else if (e instanceof AuthorityException) {
msg = "授权规则不通过";
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", msg);
jsonObject.put("code",HttpStatus.TOO_MANY_REQUESTS);
// 返回默认数据
Map<Object, Object> map = new HashMap<>();
map.put("username", "admin");
jsonObject.put("mock", map);
return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(jsonObject));
}
@PostConstruct
public void initBlockRequestHandler() {
GatewayCallbackManager.setBlockHandler(this);
}
}