Spring cloud中的基于Zuul的Api Gateway

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaoruda/article/details/88764681

在微服务架构中,后端的服务会存在多个。如果没有API Gateway就会存在以下的问题:

  • 客户端需要知道每个每个微服务的存在
  • 一次业务场景的交互需要发多次请求到多个微服务
  • 不同的微服务调用协议有可能是不同的
  • 每个微服务都需要进行权限校验

针对以上的需求,我们引入API Gateway。这里介绍基于Zuul的APIGateway的配置。

在gradle中添加依赖

buildscript {
    ext {
        springBootVersion = '2.0.4.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

sourceCompatibility = 1.8

ext {
    springCloudVersion = 'Finchley.SR1' #注意cloud的版本
}
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-actuator'
    compile 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
    compile 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
    compile('org.springframework.boot:spring-boot-starter')
}

在Application中添加@EnableZuulProxy

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

添加Zuul路由配置

application.yml文件的配置:

server:
  port: 8900
zuul:
  strip-prefix: true #是否在转发时去掉路由前缀
  prefix: /api #全局到为路由规则增加前缀
  sensitive-headers: Cookie, Set-Cookie #默认情况下Zuul在路由请求时会将Cookie、Set-Cookie和Authorization给过滤调。由于下游服务可能需要Authorization信息,所以在这里进行自定义不过滤掉Authorization。
  ignored-headers: g1 #转发时忽略的hearder
  ignored-patterns: /**/goods/user #配置不希望API网关进行路由的路径
  routes:
    goods:
      path: /goods/** #路径为goods的都会路由到goods服务中
#      serviceId: mst-goods-service #如果有服务注册中心可以使用serviceId。goods服务在Consul注册的service name
      url: http://127.0.0.1:8902
      stripPrefix: false #不移除路径前缀,即https://localhost:8900/goods/会被路由到goods服务到/goods路径,如果为true,则会被路由到goods服务到/(根路径)路径中
   host:
     connect-timeout-millis: 20000
     socket-timeout-millis: 20000
   semaphore:
       maxSemaphores: 100 # 指任意时间点允许的并发数。当请求达到或超过该设置值后,其其余就会被拒绝。默认值是100。
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 20000 #当路由转发当请求命令的时间超过该值后Hystrix会将该执行命令标记为超时并抛出异常。

ribbon:
  ServerListRefreshInterval: 1000 #设置多久刷新一次server list
  ReadTimeout: 20000 #用来这时请求连接建立之后的处理超时时间。
  ConnectTimeout: 20000 #用来设置路由转发请求的时候创建请求连接的超时时间

超时设置

在上述的配置中有三种配置超时的方式,zull.host、hystrix和ribbon。
zull.host和ribbon都是配超时的。区别在于,如果路由方式是serviceId的方式,那么ribbon的生效,如果是url的方式,则zuul.host开头的生效。也就是说使用serviceId路由和url路由是不一样的超时策略。
###stripPrex介绍

在这里再次介绍下stripPrefix,stripPrex为true时表示是否在转发时将匹配的前缀移除。比如:

zuul:
  routes:
    goods:
      path: /goods/**
      url: http://127.0.0.1:8902
      stripPrefix: false
  prefix: /api
  strip-prefix: true

如果请求:https://localhost:8900/api/goods/user 路由到goods服务的goods/user

zuul:
  routes:
    goods:
      path: /goods/**
      url: http://127.0.0.1:8902
      stripPrefix: true
  prefix: /api
  strip-prefix: true

如果请求:https://localhost:8900/api/goods/user 路由到goods服务的/user

zuul:
  routes:
    goods:
      path: /goods/**
      url: http://127.0.0.1:8902
      stripPrefix: true
  prefix: /api
  strip-prefix: false

如果请求:https://localhost:8900/api/goods/user 路由到goods服务的/api/user

zuul:
  routes:
    goods:
      path: /goods/**
      url: http://127.0.0.1:8902
      stripPrefix: false
  prefix: /api
  strip-prefix: false

如果请求:https://localhost:8900/api/goods/user 路由到goods服务的/api/goods/user

Filters

Zuul提供了如下几种类型的过滤器:

  • PRE:这种过滤器在请求被路由之前被调用。在该过滤器中可以做一些比如身份验证的事情。
  • ROUTING:这种过滤器将请求发送给最终的服务。通常来说该类过滤器使用默认的即可。
  • POST:这种过滤器在用户请求从Origin Server返回以后执行。比如在返回的response上面加response header。
  • ERROR:在其他阶段发生错误时执行该过滤器。该类过滤器定义一个即可。

请求到来时会先按照指定的顺序通过所有的前置过滤器,然后经由ROUTING路由过滤器转发给最终的服务,在获取到相应后会通过所有所有的后置过滤器。在
这些过程中出现任何问题都会跳转到错误过滤器中。在这些过滤器中通过一个RequestContext的静态类来进行数据传递的。RequestContext类中会记录和
request、response相关的数据。

RequestContext

  • getRequest: 获取HttpServletRequest
  • getResponse: 获取HttpServletResponse
  • setSendZuulResponse: 如果设置为false,则不需要进行路由,也就是不会调用api服务提供者。如果在pre filter中身份校验失败,则可以设置false
    并自定义response。
  • setResponseBody: 设置返回给客户端的response
  • setResponseStatusCode: 设置状态码

pre filter

pre filter使用如下:

@Component
public class RequestFilter extends ZuulFilter {

  private static final Logger logger = LoggerFactory.getLogger(WebSocketClientHandler.class);

  @Override
  public String filterType() {
    return "pre";
  }

  @Override
  public int filterOrder() {
    return 0;
  }

  @Override
  public boolean shouldFilter() {
    HttpServletRequest httpServletRequest = getHttpServletRequest();
    String requestURI = httpServletRequest.getRequestURI();
    return requestURI.contains("goods");
  }

  private HttpServletRequest getHttpServletRequest() {
    RequestContext currentContext = RequestContext.getCurrentContext();
    return currentContext.getRequest();
  }

  @Override
  public Object run() throws ZuulException {
    HttpServletRequest httpServletRequest = getHttpServletRequest();
    logger.info("request method {} URI {}", httpServletRequest.getMethod(),httpServletRequest.getRequestURI());
    return null;
  }
}
  • filterOrder: 指定filter被执行的顺序,值越小越先被执行。
  • shouldFilter: 指定该filter是否会被执行,为true时会执行run方法指定的逻辑,为false时跳过该filter,不执行run方法。
  • run: 该filter的核心逻辑,可以在该filter中执行比如身份校验的工作。

post filter

post filter使用如下:

@Component
public class ResponseFilter extends ZuulFilter {
  private static final Logger logger = LoggerFactory.getLogger(WebSocketClientHandler.class);

  @Override
  public String filterType() {
    return "post";
  }

  @Override
  public int filterOrder() {
    return 0;
  }

  @Override
  public boolean shouldFilter() {
    return true;
  }

  @Override
  public Object run() throws ZuulException {
    RequestContext currentContext = RequestContext.getCurrentContext();

    HttpServletResponse servletResponse = currentContext.getResponse();

    logger.info("Zuul get response, http status is: [{}]", servletResponse.getStatus());

    return null;
  }
}

在该filter中可以获取请求的返回信息,比如状态码、response等。

mst-api-gateway代码

猜你喜欢

转载自blog.csdn.net/zhaoruda/article/details/88764681