1.GateWay
使用网关的好处:
- 它提供了一个统一的入口,客户端无需知道每台服务器的ip地址,只需要给网关发送请求。
- 可以对各个微服务之间进行流量管控,服务熔断,降级等机制。
- 协议适配
- 安全防护,ip黑名单,鉴权等。
而我们一直用到的网关的功能差不多就是统一访问入口、请求路由、请求限流和鉴权。
2.GateWay网关的路由规则routes
1.id:该路由规则的唯一id,标志,名字
2.uri:需要被路由到的uri地址,比如http://www.baidu.com ,那么这个请求就会被路由到百度上去。也可以是 lb://application.name 这样的形式,lb就是load banlance负载均衡的意思,application.name填的就是要路由到的服务的名称,那么该网关就能自动的将请求负载均衡到指定的服务上去了。
3.predicates:断言(判断条件),一个请求过来就是通过predicates来判断是否可以路由到指定的route上去的,而predicates可以去通过Host、Path、Query、Method、Cookie、Header、DateTime、RemoteAddr等去进行断言,可以单个使用,也可以多个组合在一起进行使用。
4.filters:过滤器,通过pre和post方法可以对请求发送到指定服务前和请求从指定服务返回后,对该请求的数据进行修改。
gateway:
routes:
- id: product_route
uri: lb://lgmall-product
predicates:
- Path=/api/product/** #匹配对应的路径,并且会将匹配到的路径添加到uri的后面
- Query=id #请求的参数中包含一个叫id的参数
- Query=id,5 #请求的参数中包含一个叫id的参数且id的值为5
- Method=Post #请求方法的类型为Post请求
- After=2021-05-01T12:00:00.000+08:00[Asia/Shanghai] #匹配所有请求的时间在2021年5月1日12点后的请求
- RemoteAddr=192.168.56.1/0 #匹配所有远程请求地址是192.168.56.1,子网掩码是0的请求
- Header=id,\d+ #匹配所有header中包含id为数字的请求,\d+是一个正则表达式,表示任意数字
filters:
- RewritePath=/api/(?<segment>/?.*),/$\{segment} #将前面一段路径重写为后面一段路径,这里的意思是把原路径中的/api给去掉
- PrefixPath=/product #将/product加在请求路径的前面
- StripPrefix=2 #去掉前面2个/和它后面的路径,如/A/B/C,就会变成/C
- SetPath=/product/{segment} #设置路径,这里再前面需要加一个-Path=api/product/{segment},这样segment会存储到一个map中,设置路径是就能或者到
- AddRequestParameter=id,1 #给请求添加参数id=1
- SetStatus=404 #返回页面状态码status code为404,即使它是一个正常的请求
3.网关的执行流程
这张是官网上的流程图:
1.首先客户端发送请求过来的时候,会通过GateWay Handler Mapping去对请求进行路由route的映射;
2.如果映射到了,就会再调用网关处理程序GateWay Web Handler进行处理;
3.那么Handler就会通过这个route的一系列Filter对该请求进行pre处理,处理完成以后最终路由到一个具体的服务上去;
4.当请求从该服务返回的时候,又会通过这一系列Filter对请求进行post处理,再从handler到Mapping进行返回给该客户端。
4.GatewayFilter和GlobalFilter
网关过滤器根据作用范围可以分为GatewayFilter和GlobalFilter:
GatewayFilter:在配置文件中,指定路由下添加的Filter都是GatewayFilter,它只对当前的路由生效。除非可以通过spring.cloud.default-filters来进行配置,将其作用在全局上。
GloablFilter:这是全局过滤器,不需要在配置文件中去进行指定,它会作用在所有的路由上。通过GateWayFilterAdapter包装成GateWayFilterChain可识别的过滤器,他也是请求uri转换为真实请求地址的核心过滤器。
5.自定义Filter,鉴权
通过上面的介绍,我们也能够知道网关的工作流程了,那么当我们使用网关去进行鉴权的时候,就可以通过自定义一个全局的过滤器来实现。
/**
* 鉴权使用的Filter
*/
@Component
public class AccessFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
try {
String currentMemberId = MemberInfoUtil.getCurrentMemberId();
//todo 继续在这里判断和鉴权,如果鉴权失败了,也会返回earlyResponse;
} catch (InvalidTokenException e) {
return earlyResponse(e.getMessage(), exchange);
}
//返回这个chain.filter会使得继续执行下面的filter
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
private Mono<Void> earlyResponse(String message, ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Content-Type", "application/json;charset=utf-8");
response.setStatusCode(HttpStatus.UNAUTHORIZED);
String message2 = "{\"message\":\"" + message + "\"}";
DataBuffer buffer = response.bufferFactory().wrap(message2.getBytes());
//返回这个,就不会再执行filter了,就是真的返回了
return response.writeWith(Mono.just(buffer));
}
}
- 在这里我们定义一个类AccessFilter 继承自GlobalFilter和 Ordered,然后将其使用@component注解加入到spring容器中,那么这个全局过滤器就生效了。
- 不同于定义GateWayFilter,使用它需要手动的进行配置路由规则,将这个Filter加入到指定的路由规则中去,而自定义GlobalFilter是不需要这样做的。
- 在重载的filter方法中,我们只需要获取用户信息,进行权限验证的判断,有权限则返回chain.filter(exchange)方法,使得Filter链可以接着执行下去。
- 如果判断出权限不足或者无法验证身份,则会返回一个response.writeWith(Mono.just(buffer)),那么这个response就会直接返回,不会再进行后面的操作了。
6.网关限流
GateWay限流是采用的令牌桶的方式进行限流的,需要配合redis来使用,他有以下几种限流方式:1.根据URI限流;2.根据参数限流;3.根据IP限流;
注意:本文归作者所有,未经作者允许,不得转载