网关
网关:
网关 = 路由转发 + 过滤器
网关统一服务入口,可方便实现对平台众多服务接口进行管控 ,对访问服务的身份认证、防报文重放与防数据篡改、功能调用的业务鉴权、响应数据的脱敏、流量与并发控制,甚至基于API调用的计量或者计费等等。
网关的作用:
- 1.网关可以实现服务的统一管理
- 2.网关可以解决微服务中通用代码的冗余问题(如权限控制,相应数据的脱敏,流量监控,限流,基于API调用的计量和计费等)
常用的网关组件:
1.zuul
zuul是从设备和网站到Netflix流媒体应用程序后端的所有请求的前门。作为一个边缘服务应用程序,zul被构建为支持动态路由、监视、弹性和安全性。
目前zuul组件已经从1.0更新到2.0,但是作为springcloud官方不再推荐使用zuul2.0,但是依然支持zuul2.
2.Gateway
提供了一个在springmvc之上构建API网关的库。springcloudgateway旨在提供一种简单而有效的方法来路由到api,并为api提供横切关注点,比如:安全性、监控/度量和弹性。
Gateway具有如下特性:
- 基于springboot2.x 和 spring webFlux 和 Reactor 构建 响应式异步非阻塞IO模型
- 动态路由
- 请求过滤
网关的使用
网关服务是一个独立的SpringBoot应用
开发网关动态路由
1.引入gateway网关依赖:
注意:不用引入springboot-starter-web,因为gateway为了效率使用webflux进行异步非阻塞模型的实现,webflux也是一种web模型,如果因日springboot-starter-web,会产生冲突,报如下错误:
<!--引入springboot 网关中不能使用springmvc 的web模型-->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-web</artifactId>-->
<!--</dependency>-->
<!--引入consul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--引入actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--引入gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2.编写网关配置:
server:
port: 7979
spring:
application:
name: GATEWAY
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: product_router #路由对象唯一标识
uri: http://localhost:8799 #商品服务地址
predicates: #断言 用来配置路由规则
- Path=/product
#-----------当访问http://localhost:7979/product时会转发到:http://localhost:8799/product
- id: category_router #路由对象唯一标识
uri: http://localhost:8787 #类别服务地址 如:
predicates: #断言 用来配置路由规则
- Path=/category
#-----------当访问http://localhost:7979/category时会转发到:http://localhost:8787/category
3.启动服务:网关服务,商品服务,类别服务
商品服务和类别服务接口可见:服务注册中心1.3.1 ↓ http://sovzn.github.io/2021/07/27/%E6%9C%8D%E5%8A%A1%E9%97%B4%E7%9A%84%E9%80%9A%E4%BF%A1/
4.测试
直接在网关服务的端口7979下访问/category和/product:
可以发现成功转发至相应服务
Java方式配置路由(了解)
创建一个配置类(优先级高于通过配置文件配置),效果与通过配置文件配置一样:
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
//类别路由
.route("category_router", r -> r.path("/category")
.uri("http://localhost:8787"))
//商品路由
.route("product_router", r -> r.path("/product")
.uri("http://localhost:8799"))
//.....
.build();
}
}
网关的配置细节
1. - path
后可写多个路径,且支持通配符如:
- Path=/product,//product/{id},/product/**
2.配置实现网关请求转发的负载均衡,Gateway组件底层集成了Ribbon组件。
语法:uri: lb://服务id 其中lb其实就是LoadBalance
如:
server:
port: 7979
spring:
application:
name: GATEWAY
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: product_router #路由对象唯一标识
#uri: http://localhost:8799 #商品服务地址 http://localhost:8799/product
uri: lb://PRODUCT #PRODUCT:商品服务服务名,实现请求负载均衡处理
predicates: #断言 用来配置路由规则
- Path=/product,/product/{id},/product/**
- id: category_router #路由对象唯一标识
#uri: http://localhost:8787 #类别服务地址 如: http://localhost:8787/list
uri: lb://CATEGORY #CATEGORY:类别服务服务名,实现请求负载均衡处理
predicates: #断言 用来配置路由规则
- Path=/category
3.查看网关路由规则列表
gateway提供路由访问规则列表的web界面,但是默认是关闭的,如果想要查看服务路由规则可以在配置文件中开启:
management:
endpoints:
web:
exposure:
include: "*" #开启所有web端点暴露
访问路由管理列表地址:
http: //IP:网关服务端口/actuator/gateway/routes
网关的断言和过滤
常用的断言
1.Gateway支持多种方式的predicate:
- After=2020-07-21T11:33:33.993+08:00[Asia/Shanghai] `指定日期之后的请求进行路由
- Before=2021-09-20T20:38:55.675+08:00[Asia/Shanghai] `指定日期之前的请求进行路由
- Between=2021-09-20T20:38:55.675+08:00[Asia/Shanghai], 2021-09-21T20:38:55.675+08:00[Asia/Shanghai]
- Cookie=username,sovzn `基于指定cookie的请求进行路由
- Cookie=username,[A-Za-z0-9]+ `基于指定cookie的请求进行路由
`curl http://localhost:7979/product --cookie "username=sovzn"
- Header=X-Request-Id, \d+ `基于请求头中的指定属性的正则匹配路由(这里全是整数)
`curl http://localhost:7979/product -H "X-Request-Id:11"
- Method=GET,POST `基于指定的请求方式请求进行路由
- After
指定日期之后的请求进行路由:如下:在2021-09-20 20:38:55 后的请求才有效
gateway:
routes:
- id: product_router #路由对象唯一标识
#uri: http://localhost:8799 #商品服务地址
uri: lb://PRODUCT #PRODUCT:商品服务服务名,实现请求负载均衡处理 如:/product/product/list
predicates: #断言 用来配置路由规则
- Path=/product,/product/{id},/product/**
- After=2021-09-20T20:38:55.675+08:00[Asia/Shanghai]
# ---------在2021-09-20 20:38:55 后的请求才有效------
其中,after后的参数为jdk1.8后的新属性:ZonedDateTime(当前区域时间):
public class Test {
public static void main(String[] args) {
System.out.println(ZonedDateTime.now());
}
}
2021-09-20T20:50:36.804+08:00[Asia/Shanghai]
Process finished with exit code 0
测试:在2021-09-20 20:38:55之前的请求↓
请求报404
在2021-09-20 20:38:55之后的请求↓:
请求成功,返回相应数据
- cookie
基于指定cookie的请求进行路由
对于- cookie的测试,可以通过curl命令(Win10已预装curl)向请求中添加cookie键值对参数
1.指定cookie中含有某键值信息的请求: Cookie=username,sovzn
gateway:
routes:
- id: product_router #路由对象唯一标识
#uri: http://localhost:8799 #商品服务地址
uri: lb://PRODUCT #PRODUCT:商品服务服务名,实现请求负载均衡处理 如:/product/product/list
predicates: #断言 用来配置路由规则
- Path=/product,/product/{id},/product/**
- After=2021-09-20T20:38:55.675+08:00[Asia/Shanghai]
- Cookie=username,sovzn
**2.支持正则表达式: - Cookie=username,[A-Za-z0-9]+ **
**3.可以同时配置多条 - Cookie **
- Header
请求中必须还有指定的请求头:如 Header=X-Request-Id,1024
gateway:
routes:
- id: product_router #路由对象唯一标识
#uri: http://localhost:8799 #商品服务地址
uri: lb://PRODUCT #PRODUCT:商品服务服务名,实现请求负载均衡处理 如:/product/product/list
predicates: #断言 用来配置路由规则
- Path=/product,/product/{id},/product/**
- After=2021-09-20T20:38:55.675+08:00[Asia/Shanghai]
#- Before=2021-04-20T10:23:22.124+08:00[Asia/Shanghai]
#- Between=2021-04-20T10:23:22.124+08:00[Asia/Shanghai],2021-04-20T10:25:22.124+08:00[Asia/Shanghai]
#- Cookie=username,sovzn
#- Cookie=username,[A-Za-z0-9]+
- Header=X-Request-Id,1024
请求头中未加入X-Request-Id=1024的访问:
请求头中加入X-Request-Id=1024的访问:成功,并返回相应数据
- Method
指定请求的请求方式,如:- Method=GET
——- 综上。断言可以理解为一种过滤,只转发符合某种要求的请求
常用的Filter
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由筛选器的作用域是特定路由。
内置Filter
- AddRequestHeader:给转发的请求加入指定请求头信息
- AddRequestParamete:给转发的请求加入指定参数
- AddResponseHeader :给转发请求的响应加入指定头信息
- PrefixPath:给转发的请求的URL加入指定前缀信息
- StripPrefix=n:去掉锁转发的请求的n个前缀
测试:
gateway:
routes:
- id: product_router #路由对象唯一标识
#uri: http://localhost:8799 #商品服务地址
uri: lb://PRODUCT #PRODUCT:商品服务服务名,实现请求负载均衡处理
predicates: #断言 用来配置路由规则
- Path=/product,/product/{id},/product/**
- After=2021-09-20T20:38:55.675+08:00[Asia/Shanghai]
filters:
- AddRequestHeader=User-Name, sovzn
- AddRequestParameter=color, blue
- AddResponseHeader=X-Response-Red, Blue
#- PrefixPath=/mypath #加入指定前缀filter
#- StripPrefix=1 #去掉请求路径中n级前缀
- id: category_router #路由对象唯一标识
uri: lb://CATEGORY
predicates: #断言 用来配置路由规则
- Path=/category
# filters:
# - StripPrefix=1 # /list
在商品服务PRODUCT的方法中添加接收参数的方法:
@GetMapping("product")
public String product(HttpServletRequest request,String color){
System.out.println("获取Filter中设置在请求头信息:"+request.getHeader("User-Name"));
System.out.println("获取Filter中设置的请求参数:"+color);
return "product ok,当前服务端口"+port;
}
测试访问:
- PrefixPath=/mypath #加入指定前缀filter
- PrefixPath=/mypath #加入指定前缀filter
在商品服务PRODUCT中加入URL为”/mypath/product”的方法
:
@GetMapping("/mypath/product")
public String mypathproduct(HttpServletRequest request,String color){
return "product ok,URL为/mypath/product,当前服务端口"+port;
}
测试:
- StripPrefix=1 #去掉请求路径中n级前缀
不测试了🥱
注意:
如果两个路由中有同样的请求路径,如下的/list
gateway:
routes:
- id: product_router
uri: http://localhost:8799
# uri: lb://PRODUCT
predicates:
- Path=/list
- id: category_router
uri: http://localhost:8787
#uri: lb://CATEGORY
predicates:
- Path=/list
会按照路由配置顺序转发,即当通过网关服务访问/list时,会转发到http://localhost:8799/list
自定义全局Filter
注意:自定义的全局Filter是针对当前网关服务的所有请求,而在路由中配置的filters只是对当前路由要转发的请求进行一系列处理。
@Configuration
class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("进入自定义的filter");
if(exchange.getRequest().getQueryParams().get("name")!=null){
System.out.println("用户身份信息合法,放行请求继续执行!!!");
return chain.filter(exchange);
}
System.out.println("非法用户,拒绝访问!!!");
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
/**
*当有多个自定义Filter时用来排序,int数字来指定filter的执行顺序
* 默认按照自然数字进行排序,-1表示在任何filter之前执行
**/
return -1;
}
}
1.不带参直接访问:http://localhost:7979/product
2.带参name访问:
- Post link: http://sovzn.github.io/2021/09/12/Gateway/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues