API网关是一个服务器,是系统的唯一入口(也是微服务领域中重要的组件之一)。是大型分布式系统中,为了保护内部服务而设计的一道屏障,可以提供高性能、高可用的 API托管服务,从而帮助服务的开发者便捷地对外提供服务,而不用考虑安全控制、流量控制、审计日志等问题,统一在网关层将安全认证,流量控制,审计日志,黑白名单等实现。网关的下一层,是内部服务,内部服务只需开发和关注具体业务相关的实现。网关可以提供API发布、管理、维护等主要功能。开发者只需要简单的配置操作即可把自己开发的服务发布出去,同时置于网关的保护之下。
简单地说,API网关就是API们的管理者,例如能防止你要开放的API被恶意请求之类的…顺便再加上了一些负载均衡、身份验证等功能
Zuul 1.x 已经进入了维护阶段,而且Gateway是SpringCloud团队研发的,是亲儿子产品,值得信赖。而且很多功能Zuul都没有,用起来也非常简单便捷。Gateway是基于异步非阻塞模型上进行开发的,性能方面也不需要担心。虽然Netflix早就发布了最新的Zuul 2.x ,但SpringCloud貌似没有整合计划
核心逻辑:路由转发+执行过滤器链
官网总结:
客户端SpringCloud Gateway发出请求,然后在Gateway Handler Mapping中找到与之请求相匹配的路由,将其发送到Gateway Web Handler,Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会发在代理请求之前(“pre”)或之后(“post”)执行业务逻辑,这样,Filter在“pre”类型的过滤器可以做参数校验,权限校验,流量监控,日志输出,协议转换等;在“post”类型的过滤器可以做响应内容,响应头的修改,日志的输出,流量监控等有着非常重要的作用
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.baidu</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--一般基础配置类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class, args);
}
}
@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();
}
}
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/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
predicates:
- Path=/payment/lb/**
predicates:
- Path=/payment/lb/**
- After=2020-07-20T11:07:37.485+08:00[Asia/Shanghai]
predicates:
- Path=/payment/lb/**
- Before=2020-07-20T11:07:37.485+08:00[Asia/Shanghai]
predicates:
- Path=/payment/lb/**
- Between=2020-06-20T11:07:37.485+08:00[Asia/Shanghai],2020-07-20T11:07:37.485+08:00[Asia/Shanghai]
predicates:
- Path=/payment/lb/**
- Cookie=name, xh
predicates:
- Path=/payment/lb/**
- Header=X-Request-Id, \d+
predicates:
- Path=/payment/lb/**
- Host=**.baidu.com
predicates:
- Path=/payment/lb/**
- Method=GET
predicates:
- Path=/payment/lb/**
- Query=age,\d+
过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。过滤器可以限定作用在某些特定请求路径上。 Spring Cloud
Gateway包含许多内置的GatewayFilter工厂
GatewayFilter使用方法和Predicate类似,可以自主测试,毕竟有31种
举个例子:
predicates:
- Path=/payment/lb/**
filters:
- AddRequestParameter=Gateway, xuhao
测试:
可以在lb方法中获取参数,我们的请求路径是没有带参数的,没有设置AddRequestParameter Filter就获取不到,设置了,就能获取到,这个主要就是测试一下,让你们可以好理解
@GetMapping(value = "/payment/lb")
public String getPaymentLB(HttpServletRequest request)
{
String gateway = request.getParameter("Gateway");
System.out.println(gateway);
return serverPort;
}
GlobalFilter官网也有10种,但是我们实际开发中一般使用自定义的过滤器
@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;
}
}