一、介绍

1 、网关选择
  • 所有的微服务都需要网关,挡在微服务前,起到日志,限流,权鉴等作用;
  • netflix公司的zuul,zuul2;zuul功能存在一定的缺陷,zuul2进行了一定的提升;
  • Spring Cloud GataWay等网关组件: 由spring内部研发出了新的网关;
2 、zuul 1.x
  • 基于Servlet2.5 阻塞架构,Zuul用Java实现;
  • 采用非Reactor模式,基于阻塞I/O,性能较低;
3 、zuul 2.x
  • 高性能的;
4 、Spring Cloud GataWay
  • GataWay意欲取代zuul,SpringCloud 2.0以上版本中,没有对zuul2.x进行整合,只支持1.x;
  • GataWay 以 Spring Boot 2.x, Spring WebFlux, Project Reactor为基础;
  • Spring WebFlux底层 使用了高性能的Reactor模式通信框架Netty;
  • netty可以支持高并发,异步式非阻塞式;

二、组件

1. 路由(Route)

  • 构建网关的基本模块 (包含ID,目标URL,一系列的断言和过滤器组成);

2. 断言(Predicate)

  • 如果请求与断言相匹配,则进行路由,如果不匹配,则路径出错;

3. 过滤(Filter)

  • 路由进行匹配后,通过过滤器来进行前面或者后面的过滤;

三、案列演示

1. 服务提供方微服务

  • 服务提供方必须注册到注册中心,从而进行动态路由

2. GateWay网关微服务

  • 网关微服务也要入驻注册中心,从而进行动态路由

pom.xml

<dependencies>
     <!--eureka 服务端依赖-->
     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
     </dependency>

     <!--网关相关依赖,不能添加web的starter,否则报错-->
     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-gateway</artifactId>
     </dependency>
 </dependencies>

application.yaml

server:
  port: 9527

# 向注册中心注册时候的服务的名字
spring:
  application:
    name: zte-cloud-gateway


  cloud:
    gateway:
      # 可以配置多个路由的具体配置
      routes:
        - id: firstmethod_route   # 路由的名字,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001    # 转发服务的ip及端口
          predicates:
            - Path=/zte-payment-provider/consumer/getname/**    # 断言: 路径匹配 /consumer/getname/{name}

        - id: secondmethod_route
          uri: http://localhost:8001
          predicates:
            - Path=/zte-payment-provider/consumer/getage/**    # 断言: 路径匹配 /consumer/getAge/{age}

3. 访问GateWay微服务

  • 对于微服务工程,可以通过对应的ip和端口及路径进直接行访问;
  • 也可通过网关微服务的端口+ip,再配上微服务工程的路径进行访问;
  • 这个东西类似nginx;
#这个localhost代表的是原来的工程的ip及端口
http://localhost:8001/zte-payment-provider/consumer/getname/Lucy
http://localhost:8001/zte-payment-provider/consumer/getAge/10

#这个localhost代表的是网关的ip及端口
http://localhost:9527/zte-payment-provider/consumer/getname/Lucy
http://localhost:9527/zte-payment-provider/consumer/getAge/10

# 断言如果匹配到,就会将访问路径中: gateway的ip和端口替换为微服务的ip和端口

4. 路由注入方式

  • 方式一: 通过配置yaml的方式,较常用;
  • 方式二:通过代码注入路由的方式;

4.1. yaml配置,如上所示
4.2. 代码注入

package com.zte.cloud.config;

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeBuilder){
        RouteLocatorBuilder.Builder routes = routeBuilder.routes();

        /**要访问的网址: http://news.baidu.com/guonei
         * 参数一: first_gateway_route, 路由的id
         * 参数二: /guonei,  目标网站的路径,也即断言
         * 参数三: http://news.baidu.com/guonei, 目标网站的地址,其实就是域名加路径
         * 如果访问 http:localhost:9527/guonei,将会转发到 http://news.baidu.com/guonei*/
        routes.route("first_gateway_route",
                r ->r.path("/guonei").
                        uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
}

为什么没调通,因为公司内网吗?

5. 动态路由

  • 微服务进行集群部署;
  • 路由匹配:动态路由根据服务名,而不是ip+端口方式匹配,实现负载均衡(默认轮询);

Gateway的application.yaml

server:
  port: 9527

spring:
  application:
    name: zte-cloud-gateway

  cloud:
    gateway:
      discovery:
        locator:
          enabled: true   # 开启从注册中心动态创建路由的功能,利用微服务进行路由
      # 可以配置多个路由的具体配置
      routes:
        - id: firstmethod_route  
          uri: lb://ZTE-PAYMENT-PROVIDER    # 匹配注册中心的微服务的名字,lb代表开启负载均衡
          predicates:
            - Path=/zte-payment-provider/consumer/getname/**    # 断言: 

        - id: secondmethod_route
          uri: lb://ZTE-PAYMENT-PROVIDER
          predicates:
            - Path=/zte-payment-provider/consumer/getage/**    # 断言: 路径匹配 /consumer/getAge/{age}

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://firsteureka:7001/eureka/

四、常用断言

  • 多个断言,类似于sql中的and后面的条件;
  • 只有每个断言都匹配到,才会真正进行服务的转发;
  • 具体的各种断言可以去spring的官网进行查看;

1. 时间断言

  • After : 在某个时间点后,该路由才生效,
  • Before
  • Between

application.yaml

# 向注册中心注册时候的服务的名字
spring:
  application:
    name: zte-cloud-gateway

  cloud:
    gateway:
      # 可以配置多个路由的具体配置
      routes:
        - id: firstmethod_route   # 路由的名字,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001    # 匹配服务的ip及端口
          predicates:
            - Path=/zte-payment-provider/consumer/getname/**    # 断言: 路径匹配 /consumer/getname/{name}
            - After=2019-06-18T09:23:55.269+08:00[Asia/Shanghai]  # 时间格式用java8的新类来获取

main方法获取时间时间断言的格式

package com.zte.cloud;
import java.time.ZonedDateTime;
public class MainClass {
    public static void main(String[] args) {
        // Java8新增的特性,显示当前时间及当前时区
        ZonedDateTime zbj = ZonedDateTime.now();
        // 2020-06-18T09:23:55.269+08:00[Asia/Shanghai]
        System.out.println(zbj);
    }
}

2. Cookie断言

- Cookie=username, zzyy             # username:cookie的名字;   zzyy: 值的正则表达式

java 通过网关日志获取接口注解信息 java常用的网关有哪几种_微服务

3. Header断言
- Header=Request-Id, \d+            # header的名字, 正则表达式(为整数)
4. Path断言
- Path=/zte-payment-provider/consumer/getname/**    # 断言: 路径匹配 /consumer/getname/{name}
5. Method断言
- Method=GET

五、常用过滤器(Filter)

  • Web请求,在服务转发的过程中,进行一些如日志,限流,权鉴等作用;
  • 生命周期:pro(请求前过滤)和post(请求后过滤)两种;
  • 种类:GatawayFilter(单一的,31种),GlobalFilter(全局的,10种)过滤器;

1. 单一过滤器

  • 单一过滤器是对一个路由进行规定的,包含31种;
  • 以AddRequestHeader过滤器,其他的功能后续需要再去官网查看;
  • 请求经过该路由时候,增加了请求头,可以增加多个;
  • 增加的请求头,可以在被代理服务的Controller中获取;

gateway的applicaiton.yaml

# 向注册中心注册时候的服务的名字
spring:
  application:
    name: zte-cloud-gateway


  cloud:
    gateway:
      # 可以配置多个路由的具体配置
      routes:
        - id: firstmethod_route   # 路由的名字,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001    # 匹配服务的ip及端口
          predicates:
            - Method=GET
          filters:
           - AddRequestHeader=color, blue  #添加两个请求头
           - AddRequestHeader=hobby, swim

代理微服务controller

package com.zte.cloud.consumer.controller;

import javax.servlet.http.HttpServletRequest;
@RestController
public class PaymentController {

    @GetMapping("/consumer/getname/{name}")
    public String getName(@PathVariable("name") String name, HttpServletRequest request){
        return name + "======consumer服务方" +
                request.getHeader("color")+
                request.getHeader("hobby");
    }


    @GetMapping("/consumer/getAge/{age}")
    public String getName(@PathVariable("age") Integer age,  HttpServletRequest request){
        return "您的年龄为:" + age +
                request.getHeader("color")+
                request.getHeader("hobby");
    }
}

2. 全局过滤器:自定义

  • 对所有的路由进行过滤的;
  • 可以定义多个过滤器,优先级数字越小,过滤级别越高;

0号过滤器

package com.zte.cloud.filter;
@Component
public class GatewayUserNameFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入全局过滤器--用户名过滤:" + new Date());
        /** 获取访问路由时候带的请求头
         *      1.如果匹配不上,则返回错误信息
         *      2.如果匹配上,则通过,去下一个过滤链*/
        HttpHeaders headers = exchange.getRequest().getHeaders();
        List<String> list = headers.get("username");
        String username = list.get(0);
        if(username.equals("shuzhan")){
            return chain.filter(exchange);

        }else{
            System.out.println("Illegal Appler");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();

        }
    }

    @Override
    public int getOrder() {
        /**过滤器优先级: -2147483648---2147483647
         * 1. 优先级越小,级别越高*/
        return 0;
    }
}

1号过滤器

package com.zte.cloud.filter;
@Component
public class GatewayPasswordFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入全局过滤器---密码过滤:" + new Date());
        /** 获取访问路由时候带的请求头
         *      1.如果匹配不上,则返回错误信息
         *      2.如果匹配上,则通过,去下一个过滤链*/
        HttpHeaders headers = exchange.getRequest().getHeaders();
        List<String> list = headers.get("password");
        String password = list.get(0);
        if(password.equals("123456")){
            return chain.filter(exchange);

        }else{
            System.out.println("Illegal Appler");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();

        }
    }

    @Override
    public int getOrder() {
        /**过滤器优先级: -2147483648---2147483647
         * 1. 优先级越小,级别越高*/
        return 1;
    }
}

java 通过网关日志获取接口注解信息 java常用的网关有哪几种_java 通过网关日志获取接口注解信息_02