一、Gateway简介
网关,在微服务架构中,主要用来路由,增强和控制对服务的访问,同时也具备负载均衡、流量控制、访问控制等能力,SpringCloud Gateway是Spring官方基于Spring5.0、SpringBoot2.0等技术开发的网关,SpringCloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
- 第二代网关技术和SpringCloud配合更紧密,之前的网关技术是zuul
- 底层Netty(网络框架,封装了NIO)性能更好,多路复用
- 路由过滤器合理的API设计,功能更加强大
二、为什么使用网关
目前项目的问题:
- 微服务外部调用微服务集群里面的内容时,遇到问题,服务太多,需要记住所有的服务的地址
- 一个服务有很多台机器,需要做负载均衡,浏览器显然不能做这件事情
- 无法对请求进行统一的统计和过滤
网关就可以解决这些问题
- 微服务网关封装了应用程序的内部结构,客户端只需要跟网关交互,而无需直接调用特定微服务
- 方便监控,所有的请求都可以先请求网关,方便了对请求的管理和监控
- 统一过滤处理,方便管理
- 可以做负载均衡
三、Gateway使用
- 创建一个服务(coding-gateway),并注册到注册中心
- 引入gateway网关依赖
-
<!--引入gateway网关依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
-
注意:不能导入SpringBoot Web的依赖spring-boot-start-web
-
- 网关配置
-
#路由的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,那么我们需要对路径进行重写
- 方式一
#路由的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
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}
- 方式二
-
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能够以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
- 配置【以订单服务为例】
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
- 测试
-
同时开启两个订单服务,重复请求,查询是否访问的不是同一个
-
订单服务控制器
-
@RestController() public class OrderController { @Value("${server.port}") private Integer port; @GetMapping("/order") public String getOrder(){ return "订单服务测试..."+port; } }
-
六、处理跨域问题
-
spring: cloud: gateway: globalcors: corsConfigurations: '[/**]': allowedHeaders: "*" allowedOrigins: "*" allowCredentials: true allowedMethods: - GET - POST - DELETE - PUT - PATCH - OPTION server: port: 8001
-
七、自定义过滤器(GlobalFilter)
案例:判断请求中是否携带token
@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中,数值越小越先执行
}
}