乐趣区

关于springcloud:SpringCloud入门5Zuul

网上很多资源都把 API 网关,是什么,能做什么解释得十分分明,然而对于初学者来说我感觉是不够敌对的,Zuul 就是 SpringCloud 微服务中的网关。

对于初学者入门来说,只须要晓得 Zuul 就是当服务增多之后,就要对 API 进行一个对立的治理,某个类型的 API 就会调用某个类型的服务,除此之外还能对申请过去的 API 进行一个过滤。更进一步才是 Zuul 其它作用,具体有哪些作用如图所示:

本文重点解说的是 路由转发 过滤器

1 如何引入 Zuul

一样的,建设一个 Zuul 模块,本例中没有什么生产端,所以就没有采取之前建设空父模块再建设具体子模块的办法。而后往 Zuul 中的 pom 文件中增加依赖:

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

到当初整个我的项目的目录构造如图所示:

2 主启动类和配置文件

因为不波及服务生产等,只是做 api 的解决,所以主启动类还是比较简单的

@SpringBootApplication
@EnableZuulProxy        // 开启 Zuul
@EnableEurekaClient
public class ZuulMain9401 {public static void main(String[] args) {SpringApplication.run(ZuulMain9401.class, args);
    }
}

配置文件的话和惯例的 Eureka 客户端是一样的

spring:
  application:
    name: zuul9401
server:
  port: 9401

eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
  instance:
    instance-id: zuul9401

3 路由转发

路由转发次要是通过配置文件来批改,往上面配置文件中 减少内容,上面会讲 3 种形式的转发路由。

设置注册 Eureka 的服务 id

减少 第一波配置文件,是在原有的配置文件上减少了以下内容。

zuul:
  routes:
    user-a:
      path: /api-a/**
      serviceId: eureka-provide

user-a 轻易定义path 是内部拜访的门路,serviceId 是微服务配置文件的spring.application.name 的值。

所以下面减少的配置文件整体意思是,当内部拜访/api-a/ 相干门路时候,会转发给名字为eureka-provid 的服务提供服务。

开启 Eureka 服务注册核心EurekaServer8001,服务提供者EurekaProvide7001/2/3,API 网关ZuulMain9401

接着拜访 http://localhost:9401/api-a/e…eureka-provide 服务里的 eureka/provide 门路。

为了避免有点混,贴一次第一个我的项目的代码,详情请看本系列的第一篇文章。

@SpringBootApplication
@RestController
@EnableEurekaClient
public class EurekaProvide7001 {@Value("${server.port}")
    int port;

    @GetMapping("/eureka/provide")
    public String getInfo() {return "hello, i am eureka provide, the provide service. My port:" + port;}

    @GetMapping("/eureka/delayProvide")
    public String delayGetInfo() throws InterruptedException {Thread.sleep(3000);
        return "hello, delay to do something";
    }
    public static void main(String[] args) {SpringApplication.run(EurekaProvide7001.class, args);
    }
}

能够看到可能胜利 转发路由

设置 URL

减少 第二波配置文件

zuul:
  routes:
#    user-a:
#      path: /api-a/**
#      serviceId: eureka-provide
    user-b:
      path: /api-b/**
      url: http://localhost:7101/

其它如上,url 须要转发到哪个服务

通过 Edit Configurations 更改端口以及服务名以 模仿新的服务,具体操作同样在第一篇文章中有清晰的 gif 图。

其它服务不必敞开,持续开启刚新建的 Provide7101 重启 ZuulMain9401 服务,拜访 http://localhost:9401/api-b/e…

设置非注册 Eureka 的服务 id

之前在学习 Ribbon 的时候也说过,咱们能够通过 Ribbon 设置拜访一些 没有注册进 Eureka的服务,同样在 API 网关也能通过配置文件设置 Ribbon 来达到一样的成果。

减少 第三波配置文件

zuul:
  routes:
#    user-a:
#      path: /api-a/**
#      serviceId: eureka-provide
#    user-b:
#      path: /api-b/**
#      url: http://localhost:7101/
    user-c:
      path: /api-c/**
      serviceId: provide-without-eureka

#肯定须要这个才行
ribbon:
  eureka:
    enabled: false
provide-without-eureka:
  ribbon:
    ServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    listOfServers: localhost:7201, localhost:7202
    ConnectTimeout: 1000
    ReadTimeout: 3000
    MaxTotalHttpConnections: 500
    MaxConnectionsPerHost: 100

如果勾销user-a 的相干正文,此时拜访 user- a 是无奈转发的,会报 500 的谬误,我猜是因为设置了ribbon.eureka.enabled = false 的缘故。

serviceId 同样是微服务的名称,而后对这个微服务设置,所以是设置 微服务名[provid-without-eureka].ribbon,其它属性都是相干属性,最重要的同样是listOfServers,示意这个拜访这个服务名会在这些服务列表中进行调配。

为了简略还是用同一个服务,用下面的办法批改配置文件即可,批改端口号 7201,批改eureka.client.register.with.eureka = false 来模仿没有注册进 Eureka 的服务。

接着再复制一份配置,其它都不遍,把端口号改成 7202,总共是新建了端口为 7201,7202 的 两个服务

其它服务不必关,开启 ProvideWithoutEureka7201/2 服务, 重启 ZuulMain9401 服务,此时所有的服务开启如下

拜访 http://localhost:9401/api-c/e…

4 查看路由状态

顺便简略说下查看路由状态,首先还是须要减少配置文件,是 肯定要减少

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS

接着拜访 http://localhost:9401/actuato…

如果想得到详细信息,那么只须要拜访 http://localhost:9401/actuato…

5 转发路由时的 Fallback

和 Hystrix,当转发路由发现服务不可能失常提供服务的时候,就能够 fallback。

新建一个类MyFallbackProvider 实现FallbackProvider 接口

@Component
public class MyFallbackProvider implements FallbackProvider {
    @Override
    public String getRoute() {
        // 为所有的路由提供回退
        return "*";    
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable throwable) {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("something wrong, fallback now".getBytes());
            }

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

当初来手动敞开 ProvideWithoutEureka7201/2 服务模仿服务宕机,来看看是否能回退

6 过滤器

之所以 Zuul 能实现验证、受权、动态资源解决等,就是得益于上面要讲的过滤器,然而次要是讲最根本的过滤,当前可能当前进阶的时候可能再深刻讲。

创立过滤器

首先创立 filter 包,而后创立一个过滤器类 MyPreFilter 须要实现ZuulFilter 接口

public class MyPreFilter extends ZuulFilter {
    @Override
    public String filterType() {    // 过滤器类型
        return FilterConstants.PRE_TYPE;    // 申请前解决
    }

    @Override
    public int filterOrder() {        // 过滤器程序,越小越优先
        return 0;
    }

    @Override
    public boolean shouldFilter() {    // 是否开启过滤
        return true;
    }

    @Override
    public Object run() throws ZuulException {    // 执行逻辑
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        System.out.println("[ PreFilter" + "]" + String.format("send %s request to %s",request.getMethod(),request.getRequestURL()));
        return null;
    }
}

FilterConstants 类中定义了一系列常量,其中对于过滤器就是以下几种

public static final String ERROR_TYPE = "error";    // 出错时执行
public static final String POST_TYPE = "post";        // 申请后申请
public static final String PRE_TYPE = "pre";        // 申请前申请
public static final String ROUTE_TYPE = "route";    // 解决指标申请

同时再建设一个后置申请

public class MyPostFilter extends ZuulFilter {
    @Override
    public String filterType() {return FilterConstants.POST_TYPE;}

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

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

    @Override
    public Object run() throws ZuulException {RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        // 这里把 PreFilter 改为 PostFilter
        System.out.println("[ PostFilter" + "]" + String.format("send %s request to %s",request.getMethod(),request.getRequestURL()));    
        return null;
    }
}

注入容器中

新建一个 config 包,在包下创立一个类ZuulConfiguration

@Configuration
public class ZuulConfiguration {

    @Bean
    public MyPreFilter getZuulPreFilterBean() {return new MyPreFilter();
    }

    @Bean
    public MyPostFilter getZuulPostFilterBean() {return new MyPostFilter();
    }
}

此时 Zuul 模块的目录构造如下

留神,这里有个坑,就是当开启了过滤器后,会发现前一大节的 fallback 生效。

重启 ZuulMain9401 服务,并且 清空idea 输入控制台

如果是接着下面一节的内容,那么此时应该是转发的是 非注册进 Eureka 服务 的路由

拜访 http://localhost:9401/api-c/e…

创作不易,如果对你有帮忙,欢送点赞,珍藏和分享啦!

上面是集体公众号,有趣味的能够关注一下,说不定就是你的宝藏公众号哦,根本 2,3 天 1 更技术文章!!!

退出移动版