zuul网关简介

Zuul 网关的核心 是系列过滤器,可以在 Http 请求发起和响应返回期间执行 系列的过滤器。 Zuul 包括以下 四种过滤器:
1,PRE 过滤器 它是在请求路由到具体的服务之前执行的,这种类型的过滤器可 以做安全验证,例如身份验证、 参数验证等。
2,ROUTING 过滤器 它用于将请求路由到具体的微服务 。在默认情况下,它使用Http Client 进行网络请求。
3,POST 过滤器:它是在请求己被路由到微服务后执行的,一 般情况下,用作收集统计信息、指标,以及将响 传输到客户端。
4,ERROR 过滤器:它是在其他过滤器发生错误时执行的。
当一个客户端 Request 请求进入 Zuul 服务时,网关先进入“pre filter “,进行一 系列的验证、操作或者判断 然后交给“routing filter ”进行路由转发,转发到具体的服务实例进行逻辑处理、返回数据。当具体的服务处理完后,最后由“post filter” 进行处理, 该类型的处理器处理完之后,将 Response 信息返回给客户端。
 

搭建网关服务

新建eureka-zuul-client模块:

引入依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>

 

配置文件

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 5000
spring:
  application:
    name: service-zuul
zuul:
  routes:
    hiapi:
      path: /hiapi/**
      serviceId: eureka-client
#      url: http://localhost:8762  #这样写不会做负载均衡
#      serviceId: hiapi-v1
    ribbonapi:
      path: /ribbonapi/**
      serviceId: eureka-ribbon-client
    feignapi:
      path: /feignapi/**
      serviceId: eureka-feign-client
#      stripPrefix: false  有该字段,请求的"feignapi"会被转发到
#zuul.prefix: /v1  #加个前缀
#ribbon:
#  eureka:
#    enabled: false
#
#hiapi-v1:
#  ribbon:
#    listOfServers: http://localhost:8762,http://localhost:8763

 

在网关上添加熔断器

如何在 Zuul 上实现熔断功能。Zuul 实现熔断功能需要实现 ZuulFallbackProvider 接口。实现该接口有两个方法,getRoute()方法,用于指定熔断功能应用于哪些路由的服务 ,另一个方法 fallbackResponse()为进入熔断功能时执行的逻辑 。新建熔断器类MyFallbackProvider,如下:

 

@Component
class MyFallbackProvider  implements ZuulFallbackProvider {
    @Override
    public String getRoute() {
//        return "eureka-client";
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            @Override
            public String getStatusText() throws IOException {
                return "OK";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("oooops!error, i'm the fallback.".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

  

在网关上添加过滤器

实现过滤器其实很简, 只需要继承 ZuulFilter ,并实现 ZuulFilter 中的抽象方法,包括 filterType()和filterOrder(),以及 ZuulFilter 的shouldFilter ()和 Object run ()的两个方法。其中 filterType()即过滤器的类型,它有四 种类型,分别是“pre '’“ post ”“ routing ”和"error",filterOrder() 是过滤顺序,它为 Int 类型的值,值越小,越早执行该过滤器shouldFilter () 表示该过滤器是否过滤逻辑,如果为 true ,则执行 run()方法:如果为 false ,则不执行 run () 方法。 run ()方法写具体的过滤的逻辑。在本例中,检查请求的参数中是否传了token这个参数。新建MyFilter过滤器类
@Component
public class MyFilter extends ZuulFilter {

    private static Logger log = LoggerFactory.getLogger(MyFilter.class);
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

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

    @Override
    public boolean shouldFilter() {    

         RequestContext ctx = RequestContext.getCurrentContext();
          if(!ctx.sendZuulResponse()){
              return false;
            }

        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        Object accessToken = request.getParameter("token");
        if(accessToken == null) {
            log.warn("token is empty");
//false代表的意思是,这个请求最终不会被zuul转发到后端服务器,但是如果当前Filter后面还存在其他Filter,那么其他Filter仍然会被调用到 ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); try { ctx.getResponse().getWriter().write("token is empty"); }catch (Exception e){} return null; } log.info("ok"); return null; } }

启动类添加注解

@EnableZuulProxy

 

测试

启动eureka-server实例,启动两个eureka-client实例,启动eureka-feign-client,eureka-ribbon-client,eureka-zuul-client实例。浏览器依次输入http://localhost:5000/hiapi/hi?name=1212333http://localhost:5000/ribbonapi/hi?name=1212333http://localhost:5000/feignapi/hi?name=1212333测试结果

 

 

posted on 2020-02-18 00:22  欧欧专栏  阅读(253)  评论(0)    收藏  举报