一、什么是Gateway
如果没有网关,我们在开发和治理微服务架构的系统时,为了完成一个业务逻辑的功能,不得不自己调用多个服务的主机和端口,会显得繁杂,容易出错。因此微服务网关项目应运而生。
网关为微服务架构的系统提供简单、有效且统一的API路由管理,主要功能包含协议适配、协议转发、安全策略、防刷、流量控制、监控日志等。
二、入门案例
从start.sprinig.io
上一键下载包含了Gateway组件的项目即可。
然后在启动类上配置路由信息:
@SpringBootApplication
public class GatewayDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayDemoApplication.class, args);
}
// 配置路由信息
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
return builder.routes()
.route("blog_route",r -> r.path("/zhangxun")
.uri("https://blog.csdn.net"))
.route("search_route", r -> r.path("/jansen")
.uri("https://www.zhihu.com/"))
.build();
}
}
以上配置路由信息主要定义了如下三个要素:
- 路由ID,此处就是
blog_route
,可以自定义; - 路由断言,此处就是
/zhangxun
,凡是符合这个路由断言的访问路径都会被通过; - 路由目标,此时就是
https://blog.csdn.net
;
当我们访问Gateway项目时,如果访问路径上包含"/zhangxun",网关就会将请求转发到"https://blog.csdn.net"上,我们启动如上的项目,然后访问“http://localhost:8080/zhangxun”就会看到,最终访问到的是CSDN的网址。
在实际开发中,一般都会采用配置文件的方式,而不是如上代码配置的方式。因为配置文件内容可以托管到统一配置中心,给与服务治理更大的灵活性。如下是等价的配置文件形式:
spring:
application:
name: gateway-demo-service
cloud:
gateway:
routes:
- id: blog_route
# uri: lb://注册中心的服务名称
uri: https://blog.csdn.net
predicates:
- Path=/zhangxun
- id: search_route
# uri: lb://注册中心的服务名称
uri: https://www.zhihu.com/
predicates:
- Path=/jansen
三、路由断言
Gateway包含了很多的路由断言工厂,当请求达到Gateway的时候,配置好的的路由断言工厂就会根据配置的路由规则,对请求进行断言匹配,只有匹配成功才会进入到下一步的处理中,否则断言失败就会直接返回错误信息。
如下是Gateway支持的一些断言工厂,分别在不同的场景下可以配置使用:
3.1 Datetime
假设我们设定一个标准时间,这个标准时间是某热销产品的开卖时间,只有当达到这个开卖时间时,用户购买请求才可以被转发到购买的服务上。此时我们就需要用到Datetime分类中的AfterRoutePredicateFactory。
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder){
// 设置一小时前的时间为标准时间
ZonedDateTime standardTime = LocalDateTime.now().minusHours(1).atZone(ZoneId.systemDefault());
return builder.routes()
.route("after_route", r -> r.after(standardTime)
.uri("https://www.zhihu.com/"))
.build();
}
假设我们的热销产品有一个截止买卖时间,超过这个时间就不能再购买,那么可以使用Datetime分类的BeforeRoutePredicateFactory。
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder){
// 设置一小时后的时间为标准时间
ZonedDateTime standardTime = LocalDateTime.now().plusHours(1).atZone(ZoneId.systemDefault());
return builder.routes()
.route("after_route", r -> r.before(standardTime)
.uri("https://www.zhihu.com/"))
.build();
}
同样的,我们还可以设置一个时间段,在这个时间段内的请求才是合法的,使用Datetime分类的BetweenRoutePredicateFactory。
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder){
// 设置一小时前的时间为开始时间
ZonedDateTime startTime = LocalDateTime.now().minusHours(1).atZone(ZoneId.systemDefault());
// 设置一小时后的时间为截止时间
ZonedDateTime endTime = LocalDateTime.now().plusHours(1).atZone(ZoneId.systemDefault());
return builder.routes()
.route("after_route", r -> r.between(startTime, endTime)
.uri("https://www.zhihu.com/"))
.build();
}
3.2 Cookie
我们还可以设定对请求的cookie内容进行断言:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("cookie_route", r -> r.cookie("name", "zhangsan")
.uri("https://www.zhihu.com/"))
.build();
}
在测试的时候,我们使用postman进行,首先输入期望的cookie内容进行测试:
然后输入非期望的cookie内容进行测试:
3.3 Weight
基于路由权重的断言,指定路由分组和权重值即可使用:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("weight_route_1", r -> r.weight("w1", 5)
.uri("https://www.zhihu.com/"))
.route("weight_route_2", r -> r.weight("w1", 95)
.uri("https://blog.csdn.net"))
.build();
}
这里配置了两个路由,它们属于同一个路由分组w1,但是知乎网站的转发权重为5%,csdn网站的转发权重为95%,那么我们的请求将有95%概率会被转发到csdn去。
3.4 Header
Header中的某个属性值必须符合预期才会通过;
3.5 Host
请求来源域名必须是预期的才会通过;
3.6 Method
请求的方法必须是预期的才会通过;
3.7 Path
已经在第二节入门案例中演示过,符合预期路径才会通过;
3.8 Query
对请求路径中的参数内容进行断言;
3.9 RemoteAddr
基本同Host,只不过此时应该写IP地址或者网段;
四、内置Filter
过滤器的作用就是可以按照应用场景修改请求和返回的内容,总的来说,Filter可以分为如下七类,但是不限于以下这些Filter:
4.1 Header
对于匹配上的请求加上header内容:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("add_request_header_route", r -> r.path("/zhangxun")
.filters(f -> f.addRequestHeader("name", "zhangsan"))
.uri("https://www.zhihu.com/"))
.build();
}
4.2 Parameter
会在请求地址后面增加上请求参数:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("add_request_parameter_route", r -> r.path("/zhangxun")
.filters(f -> f.addRequestParameter("name", "zhangsan"))
.uri("https://www.zhihu.com/"))
.build();
}
4.3 Path
StripPrefixGatewayFitlerFactory是用于去除请求前缀,而PrefixPathGatewayFilterFactory是用于增加请求前缀。
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/zhangxun/jansen")
.filters(f -> f.stripPrefix(2))
.uri("https://www.zhihu.com/"))
.build();
}
如上前缀过滤器在我们访问http://localhost:8080/zhangxun/jansen
的时候,会把路径前缀的前两个去掉再进行转发https://www.zhihu.com/
。
4.4 Status
4.5 Redirect
4.6 Hystrix
4.7 RateLimeter
部分实例暂未涉及,后续再补充。