网关,在微服务架构中,主要用来路由,增强和控制对服务的访问,同时也具备负载均衡、流量控制、访问控制等能力,SpringCloud Gateway是Spring官方基于Spring5.0、SpringBoot2.0等技术开发的网关,SpringCloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
第二代网关技术和SpringCloud配合更紧密,之前的网关技术是zuul
底层Netty(网络框架,封装了NIO)性能更好,多路复用
路由过滤器合理的API设计,功能更加强大
二、为什么使用网关
目前项目的问题:
微服务外部调用微服务集群里面的内容时,遇到问题,服务太多,需要记住所有的服务的地址
一个服务有很多台机器,需要做负载均衡,浏览器显然不能做这件事情
无法对请求进行统一的统计和过滤
网关就可以解决这些问题
微服务网关封装了应用程序的内部结构,客户端只需要跟网关交互,而无需直接调用特定微服务
方便监控,所有的请求都可以先请求网关,方便了对请求的管理和监控
统一过滤处理,方便管理
可以做负载均衡
三、Gateway使用
创建一个服务(coding-gateway),并注册到注册中心
引入gateway网关依赖
XML <!--引入gateway网关依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> |
注意:不能导入SpringBoot Web的依赖spring-boot-start-web |
网关配置
Properties #路由的id 可以认为是当前路由规则的名字 要求唯一性 spring.cloud.gateway.routes[0].id=product_route #匹配后的路由地址 【目标服务地址】 spring.cloud.gateway.routes[0].uri=http://localhost:8080 #断言 也就是匹配规则 spring.cloud.gateway.routes[0].predicates[0]=Path=/coding-product/** #路由的id 可以认为是当前路由规则的名字 要求唯一性 spring.cloud.gateway.routes[1].id=order_route #匹配后的路由地址 【目标服务地址】 spring.cloud.gateway.routes[1].uri=http://localhost:8090 #断言 也就是匹配规则 spring.cloud.gateway.routes[1].predicates[0]=Path=/coding-order/** server.port=8001 |
启动项目测试
http://localhost:网关服务端口/coding-product/products
四、路径重写
后台接口:http://localhost:8001/coding-order/order,如果前端调用时,地址为http://localhost:8001/api/coding-order/order,那么我们需要对路径进行重写
方式一
Properties #路由的id 可以认为是当前路由规则的名字 要求唯一性 spring.cloud.gateway.routes[1].id=order_route #匹配后的路由地址 【目标服务地址】 spring.cloud.gateway.routes[1].uri=http://localhost:8090 #断言 也就是匹配规则 # 1、添加上api spring.cloud.gateway.routes[1].predicates[0]=Path=/api/coding-order/** # 2、对路径进行重写,把/api/coding-order重写成/coding-order spring.cloud.gateway.routes[1].filters[0]=RewritePath=/api/coding-order(?<segment>/?.*),/coding-order/$\{segment} server.port=8001 |
YAML spring: cloud: gateway: routes: - id: order_route uri: http://localhost:8090 predicates: - Path=/api/coding-order/** filters: - RewritePath=/api/coding-order(?<segment>/?.*),/coding-order/$\{segment} |
方式二
YAML spring: cloud: gateway: routes: - id: order_route uri: http://localhost:8090 predicates: - Path=/api/coding-order/** filters: # - RewritePath=/api/coding-order(?<segment>/?.*),/coding-order/$\{segment} # 去除Path中前两个路径 - StripPrefix=2 # Path中路径换成/coding-order - PrefixPath=/coding-order server: port: 8001 |
五、动态路径(负载均衡)
Gateway能够以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
配置【以订单服务为例】
YAML spring: cloud: gateway: routes: - id: order_route # uri: http://localhost:8090 uri: lb://coding-order predicates: - Path=/api/coding-order/** filters: # - RewritePath=/api/coding-order(?<segment>/?.*),/coding-order/$\{segment} - StripPrefix=2 - PrefixPath=/coding-order - id: product_route uri: lb://coding-product predicates: - Path=/coding-product/** server: port: 8001 |
测试
同时开启两个订单服务,重复请求,查询是否访问的不是同一个
订单服务控制器
Java @RestController() public class OrderController { @Value("${server.port}") private Integer port; @GetMapping("/order") public String getOrder(){ return "订单服务测试..."+port; } } |
六、处理跨域问题
YAML spring: cloud: gateway: globalcors: corsConfigurations: '[/**]': allowedHeaders: "*" allowedOrigins: "*" allowCredentials: true allowedMethods: - GET - POST - DELETE - PUT - PATCH - OPTION server: port: 8001 |
七、自定义过滤器(GlobalFilter)
案例:判断请求中是否携带token
Java @Component public class MyGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //某个参数 对不对 String username = exchange.getRequest().getQueryParams().getFirst("username"); if (username==null) { //拦截 // 设置响应状态码 exchange.getResponse().setStatusCode(HttpStatus.MULTI_STATUS); return exchange.getResponse().setComplete(); } //放行 return chain.filter(exchange); } @Override public int getOrder() { return 0; // 多个Filter中,数值越小越先执行 } } |