概述简介
官网:https://spring.io/projects/spring-cloud-gateway
SpringCloud Gateway使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架。
可以做什么:
- 反向代理
- 鉴权
- 流量监控
- 熔断
- 日志监控等
特性:
- 基于Spring Framework 5,Project Reactor和Spring Boot 2.0进行构建;
- 动态路由能够匹配任何请求属性;
- 可以对路由指定Predicate(断言)和Filter(过滤器);
- 集成Hystrix的断路器功能;
- 集成SprigCloud服务发现功能;
- 易于编写的Predicate(断言)和Filter(过滤器);
- 请求限流功能;
- 支持路径重写。
三大核心概念
Route(路由):是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。
Predicate(断言):参考Java8的java.util.function.Predicate。开发人员可以匹配HTTP请求中的所有内容(例如请求头、请求参数),如果请求与断言相匹配则进行路由。
Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
Gateway工作流程
入门配置
- 新建Module(cloud-gateway-gateway9527)
- POM
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- YML
server:
port: 9527
spring:
application:
name: cloud-gateway
eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
- 业务类(无)
- 主启动类
package com.jiao.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author jyl
* @create 2021-3-5
*/
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class,args);
}
}
- 9527网关如何做路由映射
cloud-provider-payment8001注意controller的访问地址:@GetMapping(value = "/payment/lb")
...
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("*****查询结果:"+payment);
if (payment != null){
return new CommonResult(200,"查询成功,serverPort:"+serverPort,payment);
}else {
return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
}
}
...
@GetMapping(value = "/payment/lb")
public String getPaymentLB(){
return serverPort;
}
目前不想暴露8001端口,希望在8001外面套一个9527。
- YML新增网关配置
...
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_rout #路由的ID,没有固定规则,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_rout #路由的ID,没有固定规则,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
...
- 测试(启动7001、8001、9527)
出现一个错误:
(1)方法一:pom中的gateway添加exclusive
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</exclusion>
</exclusions>
</dependency>
(2)方法二:去掉
<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>
http://localhost:8001/payment/get/4
http://localhost:9527/payment/get/4
解决办法:
访问测试:
网关的路由的两种配置方式:
(1)在配置文件yml中配置
(2)在代码注入@RouteLocator的Bean
访问http://localhost:9527/guonei会跳转到http://news.baidu.com/guonei
package com.jiao.springcloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GateWayConfig {
//访问http://localhost:9527/guonei会跳转到http://news.baidu.com/guonei
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route_jiao1",
r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}
通过微服务名实现动态路由
(1)启动7001、8001、8002
(2)pom
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
(3)yml
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
lower-case-service-id: true #将请求路径上的服务名配置为小写(因为服务注册的时候,向注册中心注册时将服务名转成大写的了,比如以/service-hi/*的请求路径被路由转发到服务名为service-hi的服务上
enabled: true #表明gateway开启服务注册和发现的功能,并且spring cloud gateway自动根据服务发现为每一个服务创建了一个router,# 这个router将以服务名开头的请求路径转发到对应的服务
routes:
- id: payment_rout1 #路由的ID,没有固定规则,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_rout2 #路由的ID,没有固定规则,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
(4)启动9527
(5)测试
Predicate的使用
运行9527后台打印的:
写一个测试单元:
import java.time.ZonedDateTime;
public class Test1 {
public static void main(String[] args) {
ZonedDateTime zbj = ZonedDateTime.now();
System.out.println(zbj);
//2021-03-08T19:40:20.717+08:00[Asia/Shanghai]
}
}
YML配置的地方:
...
- id: payment_rout2 #路由的ID,没有固定规则,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
- After=2021-03-08T19:40:20.717+08:00[Asia/Shanghai] #这个时间之后访问有效 #After、Before、Between
- Cookie=chocolate, ch.p #参数:Cookie Name,正则表达式
- Header=X-Request-Id, \d+ #请求头要含有X-Request-Id属性并且值为整数的正则表达式
# Host【=**.jiao.com】、Method【=GET】、Path【=上面的】、Query【=username,\d+】
...
常用测试工具:
- jmeter:压力测试
- postman:post请求
- curl:模拟post、get
小结:就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理
Filter的使用
不是Spring的,而是Springcloud Gateway的。
(1)GatewayFilter【31种】https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
举例子:
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-red, blue
(2)GlobalFilter【10种】
举例子:
spring:
cloud:
gateway:
routes:
- id: resource
uri: http://localhost:9000
predicates:
- Path=/resource
filters:
- TokenRelay=
自定义过滤器:
全局日志记录、统一网关鉴权...
package com.jiao.springcloud.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Date;
@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,非法用户。");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
测试:http://localhost:9527//payment/lb?umane=123