准备
搭建一个eureka服务器和一个普通web模块,然后搭建网关模块。。
测试用的普通接口
@GetMapping(value = "/payment/get/{id}")
public Result<Payment> getPaymentById(@PathVariable("id") Long id) {
Payment payment = paymentService.getPaymentById(id);
if(payment != null) {
return new Result<>(200,"查询成功,serverPort: "+8081,payment);
}else{
return new Result<>(444,"没有对应记录,查询ID: "+ id,null);
}
}
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
使用很方便,有两种配置方式,一种是配置文件,一种是注入Bean
简单入门
server:
port: 9527
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
eureka:
instance:
instance-id: gateway
prefer-ip-address: true #显示ip地址
client:
#表示是否将自己注册进Eurekaserver默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
打开浏览器http://localhost:9527/payment/get/1可以查询到结果
相同功能的bean配置也非常简单
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
return routes.route("paymentRouter",
r->r.path("/payment/get/**")
.uri("http://localhost:8001")).build();
}
动态路由配置
将测试结构变成一个服务集群,一个eureka7001+服务提供者8000+服务提供者8001。默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能(不写死地址)。
修改yml文件开启动态路由
discovery:
locator:
enabled: true # 开启动态路由
全部yml
server:
port: 9527
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://payment # payment是微服务名
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
discovery:
locator:
enabled: true # 开启动态路由
eureka:
instance:
instance-id: gateway
prefer-ip-address: true #显示ip地址
client:
#表示是否将自己注册进Eurekaserver默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
等价于yml开启动态路由后
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
return routes.route("paymentRouter",
r->r.path("/payment/get/**")
.uri("lb://payment")).build();
}
访问http://localhost:9527/payment/get/1,发现可以实现基本的轮询负载均衡8000/8001
注意
Gateway的负载均衡依然使用的是ribbon,按照ribbon的加@RibbonClient注解的配置就好
常用的predicate
bean中多个predicate可以用and方法连接
- The After Route Predicate Factory
- The Before Route Predicate Factory
- The Between Route Predicate Factory 请求时间的限制
- The Cookie Route Predicate Factory 请求cookie的限制
- The Header Route Predicate Factory 请求头的限制
- The Host Route Predicate Factory
- The Method Route Predicate Factory 请求方法的限制 get、post。。。
- The Path Route Predicate Factory (上边使用的)
- The Query Route Predicate Factory 查询条件限制
- The RemoteAddr Route Predicate Factory
- The weight Route Predicate Factory
//before、between也一样
public RouteLocator after(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
//这个时间段后会被匹配
ZonedDateTime zonedDateTime = ZonedDateTime.now();
return routes.route("paymentRouter",
r->r.after(zonedDateTime)
.uri("lb://payment")).build();
}
//header请求匹配也是一样的
public RouteLocator cookie(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
return routes.route("paymentRouter",
//一个是cookie的名字,一个是正则表达式,合适才会执行
r->r.cookie("key","regex")
.uri("lb://payment")).build();
}
过滤器
@Component
public class LogFilter implements GlobalFilter , Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("我是全局过滤器 " + new Date());
String username = exchange.getRequest().getQueryParams().getFirst("username");
if (username==null){
System.out.println("用户名不存在o(╥﹏╥)o " + new Date());
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
//数字越小,优先级越高
@Override
public int getOrder() {
return 0;
}
}