参考:https://www.kancloud.cn/qingshou/aaa1/2667213
源码请看此系列教程(1)
使用的优缺点
面向前端开发人员更加友好,前端开发人员面向的入口减少,便于维护
服务访问的认证鉴权更加方便,可以放在API网关统一去做。避免分散造成的开发及维护成本。
访问日志、限流等公共服务也可以在网关上集中完成。避免分散造成的开发及维护成本。
说了API网关的这么多好处,那么有没有坏处呢?也是有的,而且很重要。当你使用了API网关之后,所有的请求都要多一次转发,造成一定程度上的响应时长的延长
当你使用了API网关之后,意味着网关作为流量入口需要承担比微服务更多的流量负载。所以网关本身的架构性能及稳定性非常重要。
虽然我们可以在网关的前面再去加一层nginx或者haproxy等负载均衡器,但是仍旧很难改变网关在一定程度上的流量集中的问题。
正如笔者所说网关本身的架构性能及稳定性非常重要。然而性能就是Zuul的短板,因为它是基于servlet的阻塞IO模型开发的
Zuul 1.0在netflix官方已经进入了维护阶段,netflix对Spring Cloud社区的支持也已经基本属于“88了您哎”的状态
虽然Netflix很早就宣称了要对zuul进行升级改造,也就是Zuul 2.0,但是目前与Spring Cloud的整合也处于难产状态
基于以上的原因,Spring 社区自己开发了Spring Cloud gateWay。采用了spring 官方的响应式非阻塞框架webflux。官网测试结果性能是Zuul的1.6倍。
开始学习
我们使用以下几个服务
然后看下使用方式
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
解释
route(路由):路由实网关的基础元素,由id、目标url、predicate和filter组成。当请求通过网关的时候,由Gateway Handler Mapping通过predicate判断是否与路由匹配,当predicate=true的时候,匹配到对应的路由。
predicate(谓词逻辑):是java8中提供的一个函数,允许开发人员根据其定义规则匹配请求。比如根据请求头、请求参数来匹配路由。可以认为它就是一个匹配条件的定义。
filter(过滤器):对请求处理之前之后进行一些统一的业务处理、比如:认证、审计、日志、访问时长统计等。
我们要演示的是请求到网关–》网关按照我们配置的路由,断言规则进行服务转发
首先把自定义的过滤器整个类注释掉
启动好这5个服务
访问:localhost:9527/payment/lb
可以看到请求成功
再试一次
可以看到,配置的其他路由也测试成功
自定义filter,或者直接在配置文件配置,以下是filter的示例配置
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: http://httpbin.org:80/get
filters:
- AddRequestHeader=X-Request-Foo, Bar
predicates:
- Method=GET
自定义filter(代码中有此示例)
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{
@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,非法用户,o(╥﹏╥)o");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder()
{
return 0;
}
}
自定义路由(代码中由此示例)
@Configuration
public class GateWayConfig
{
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
{
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route_atguigu",
r -> r.path("/guonei")
.uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}
重启gateway的服务,测试一下效果
还是请求/get/1接口
可以看到已生效,然后把此filter代码注释,不然会影响自定义路由的测试
访问:localhost:9527/guonei
演示完毕