网关
1、什么是路由网关
网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能。它将"1对N"问题转换成了"1对1”问题。通过服务路由的功能,可以在对外提供服务时,只暴露 网关中配置的调用地址,而调用方就不需要了解后端具体的微服务主机。
2、为什么要使用微服务网关
不同的微服务一般会有不同的网络地址,而客户端可能需要调用多个服务接口才能完成一个业务需求,若让客户端直接与各个微服务通信,会有以下问题:
(1)客户端会多次请求不同微服务,增加了客户端复杂性
(2)存在跨域请求,处理相对复杂
(3)认证复杂,每个服务都需要独立认证
(4)难以重构,多个服务可能将会合并成一个或拆分成多个
3、网关的优点
微服务网关介于服务端与客户端的中间层,所有外部服务请求都会先经过微服务网关客户只能跟微服务网关进行交互,无需调用特定微服务接口,使得开发得到简化
SpringCloud Gateway
1.SpringCloud Gateway 是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
2.SpringCloud Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如:安全、监控、指标和限流。
3.SpringCloud Gateway的概念
(1)Route(路由):路由时构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由将路由进行转发
(2)Predicate(断言):开发人员可以匹配HTTP请求中的所有内容(例如请求头、参数或者请求地址),如果请求与断言相匹配则进行路由
(3)Filter(过滤):可以在请求被路由前或者之后对请求进行修改
(4)流程
web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化的控制。predicate就是我们的匹配条件;而Filter,就可以理解为拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了。
实际操作
1.准备一个注册中心,这里不再赘述
2.添加SpringCloud Gateway的依赖,不要忘记剔除web模块,否则启动时将会报错
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--gateway 不需要web模块,否则报错-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>-->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>-->
3.更改配置文件,向注册中心进行注册,且开启动态路由识别功能
server.port=9527
spring.application.name=cloud-gateway
#eureka实例名称
eureka.instance.hostname=cloud-gateway-service
#表示向注册中心注册自己
eureka.client.register-with-eureka=true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
eureka.client.fetch-registry=true
#设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址
eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka/
#开启动态路由的识别功能
spring.cloud.gateway.discovery.locator.enabled=true
#设置路由id
spring.cloud.gateway.routes[0].id=payment_routh
#设置路由的uri
#spring.cloud.gateway.routes[0].uri=http://localhost:8001
spring.cloud.gateway.routes[0].uri=lb://CLOUD-PAYMENT-SERVICE
#设置路由断言,代理serviceId为auth-service的/auth/路径
spring.cloud.gateway.routes[0].predicates[0]=Path=/payment/get/**
#设置路由id,唯一
spring.cloud.gateway.routes[1].id=payment_routh2
#设置路由的uri
spring.cloud.gateway.routes[1].uri=lb://CLOUD-PAYMENT-SERVICE
#设置路由断言,路径匹配的进行路由
spring.cloud.gateway.routes[1].predicates[0]= Path=/payment/lb/**
4.添加网关进行配置
#设置路由id
spring.cloud.gateway.routes[0].id=payment_routh
#设置路由的uri
#spring.cloud.gateway.routes[0].uri=http://localhost:8001
spring.cloud.gateway.routes[0].uri=lb://CLOUD-PAYMENT-SERVICE
#设置路由断言,代理serviceId为auth-service的/auth/路径
spring.cloud.gateway.routes[0].predicates[0]= Path=/payment/get/**
5.全局过滤器的实现,局部过滤器实现GatewayFilter与Ordered
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*******com in MyGatewayFilter: "+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
//验证失败
if (StringUtils.isBlank(uname)){
log.info("********用户名为null,非法用户名,");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
//验证通过
return chain.filter(exchange);
}
//设置filter的优先级
@Override
public int getOrder() {
return 0;
}
}
6.除了配置文件的方式外,同时也可以通过编码进行配置
@Configuration
public class GatewayConfig {
@Bean
public MyGlobalFilter myGatewayFilter(){
return new MyGlobalFilter();
}
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route_gn",r -> r.path("/guonei").uri("http://news.baidu.com/")).build();
routes.route("path_route_gj",r -> {
return r.path("/guoji").and().host("**.gateway.com:9527").uri("http://news.baidu.com/");
}).build();
return routes.build();
}
}
7.aaa.gateway.com满足Predicate与Filter的匹配规则时访问成功,否则报404错误
- 成功
- 失败