视频学习地址:https://www.bilibili.com/video/BV18E411x7eT
源码地址:https://gitee.com/zhu_xinmiao/springcloud
spring cloud版本:H版
Gateway网关实际上就是在微服务前套了一层包装,使微服务的端口不会直接暴露给使用者,提高了安全性。
类似于网关端口9527,服务端端口8001,在设置网关后,对于8001端口方法的使用不会在去访问8001端口,而是访问localhost:9527。
三大核心概念
- 路由 route
- 断言 predicate
- 过滤器 filter
搭建
-
写pom,主要是引入以下依赖,此外gateway不需要web依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
-
写yml
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: routes: - id: payment_routh uri: http://localhost:8001 predicates: - Path=/payment/get/** - id: payment_routh2 uri: http://localhost:8001 predicates: - Path=/payment/lb/** eureka: instance: hostname: cloud-gateway-service client: service-url: register-with-eureka: true fetch-registry: true defaultZone: http://eureka7001.com:7001/eureka
路由部分解释如下:
-
写主启动类
@SpringBootApplication @EnableEurekaClient
除了用yml配置路由外,还可通过写config文件配置路由。
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator CustomRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); //类似于yml中的routes
/**
* path_route_zxm"相当于yml中routes下的id
* r -> r.path("/guonei")
* .uri("http://news.baidu.com/guonei")).build();
* 表示你访问9527/guonei,会转发到
* http://news.baidu.com/guonei
*/
routes.route("path_route_zxm",
r -> r.path("/guonei")
.uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}
配置动态路由
对yml中路由的配置进行修改
cloud:
gateway:
discovery:
locator:
enabled: true #开启注册中心路由功能
routes:
- id: payment_routh
# uri: http://localhost:8001
uri: lb://cloud-payment-service #此处如果有问题,请注意依赖spring-cloud-starter-netflix-eureka-client依赖不能错
predicates:
- Path=/payment/get/**
- id: payment_routh2
# uri: http://localhost:8001
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
测试http://localhost:9527/payment/lb时会在8001/8002两个端口间切换,实现负载均衡。
这里我出现了一个问题,8001和8002注册不进eureka,查到以下解决方法https://www.cnblogs.com/sxdcgaq8080/p/9843912.html
一条一条排查后,发觉唯一可能出错的地方应该是eureka的地址有问题,排查8001和8002的yml发现eureka的路径都为集群模式defaultZone: http://localhost:7001/eureka ,http://eureka7002.com:7002/eureka
改为单机模式defaultZone: http://localhost:7001/eureka后成功注册进eureka
常用的Predicate
-
Path
- Path=/payment/lb/**
表示判断的路径,路径符合路由就会跳转到这个路径
-
- After=2020-07-31T19:50:32.545+08:00[Asia/Shanghai]
表示判断的时间,只有时间在这个之后路由才会跳转到这个页面否则会报404错误。实际应用时,类似于秒杀系统定好时间,只有到点了才能进入抢票环节。
这里重要的是如何得到对应的时区时间,这里写了一个测试类来演示获取时区的方法。
public static void main(String[] args) { ZonedDateTime zbj = ZonedDateTime.now(); System.out.println(zbj); }
-
- Cookie=cookiename, zxm
表示需要带上cookie访问,不带的话会报404错误,curl测试如下:
其他属性类似,具体可看https://blog.csdn.net/u012367513/article/details/86356708这篇博客中的介绍。
Filter
Route filters可以通过一些方式修改HTTP请求的输入和输出,针对某些特殊的场景,Spring Cloud Gateway已经内置了很多不同功能的GatewayFilter Factories。
可以通过官方文档进行查询,也可通过该网址进行学习。
这里主要讲讲自定义的filter。
@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
/**
* 简单过滤了用户名为空的非法用户
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*****come in MyLogGatewayFilter: " + new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null){
log.info("*****用户名为null,非法用户");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange); //放行
}
/**
* 表示加载过滤器的顺序,一般越小越优先
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
这里简单过滤了用户名为空的非法用户,但在测试时出现了问题,输入正常用户名,返回的也是404,经过测试发现并没有进过滤方法。
经过仔细排查后,发现是之前写的断言没有注释,断言中要求有cookie才能正常访问,注释掉后即可正常运行。