zoukankan      html  css  js  c++  java
  • (六)Spring Cloud 网关Zuul

    Zuul作为网关,在Spring Cloud中 常可以作为以下的作用使用

    1. 和eureka-client,Ribbon,Feign结合可以实现智能路由和负载均衡的功能

    2. 将所有服务的API统一聚合,外界调用API时由网关统一对外暴露,能起到保护API接口的作用

    3. 网关可以做统一的身份和权限验证

     

     下面我们将对网关Zuul进行学习,主要有路由,负载均衡,熔断器,过滤器等,设计到的模块有

      eureka-server 7001 

      eureka-client  7002 7003

      eureka-ribbon-client 7004

      eureka-zuul-client  8000

     其中 eureka-server, eureka-client, eureka-ribbion-client 和我们前几章的module一样,为了加强记忆,我们再来做一次完整的配置

    1. 新建maven项目eurekazuul

     删掉src目录,在pom中添加 

    <packaging>pom</packaging>

    2. 配置eureka-server

        2.1 pom.xml 

      

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
                <scope>compile</scope>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-sleuth</artifactId>
            </dependency>

       2.2 启动类

       

    package com.devin.eurekaserver;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @EnableEurekaServer
    @SpringBootApplication
    public class EurekaServerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaServerApplication.class, args);
        }
    
    }
    

     2.3 权限配置类

        

    package com.devin.eurekaserver.config;
    
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //关闭csrf
            super.configure(http);
            //开启认证
            http.csrf().disable();
        }
    }
    

     

       2.4  application.yml 配置文件

       eureka-server的启动端口 7001

    server:
      port: 7001 #启动端口
    spring:
      #应用名称
      application:
        name: eureka-server
      #安全配置
      security:
        basic:
          enabled: true
        user:
          name: dev
          password: 123456
    
    #eureka配置
    eureka:
      server:
        #设置扫描失效服务的间隔时间
        eviction-interval-timer-in-ms: 20000
        enable-self-preservation: true
      instance:
        hostname: localhost
        leaseRenewalIntervalInSeconds: 10
        health-check-url-path: /actuator/health
      client:
        register-with-eureka: false  #false:不作为一个客户端注册到注册中心
        fetch-registry: false        #为true时,可以启动,但报异常:Cannot execute request on any known server
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
    # health endpoint是否必须显示全部细节。默认情况下, /actuator/health 是公开的,并且不显示细节。
    # 设置actuator开关
    management:
      security:
        enabled: false
      endpoints:
        web:
          exposure:
            include: "*"
      endpoint:
        health:
          show-details: ALWAYS

     3. eureka-client配置

         3.1 pom.xml

       

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.1.8.RELEASE</version>
            </dependency>

         3.2  启动类

        

    package com.devin.eurekaclient;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @EnableEurekaClient
    @SpringBootApplication
    public class EurekaClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaClientApplication.class, args);
        }
    
    }
    

     

         3.3 controller类

       

    package com.devin.eurekaclient.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author Devin Zhang
     * @className HelloController
     * @description TODO
     * @date 2020/3/31 10:26
     */
    @RestController
    public class HelloController {
    
        @Value("${server.port}")
        private String port;
    
        @GetMapping("/sayHello")
        public String sayHello(String name) {
            return "hello " + name + ", Warmly welcome from port:" + port;
        }
    }
    

     

         3.4 application.yml 配置类

         后续eureka-client将启动2个实例,7002 , 7003 

      

    eureka:
      auth:
        user: dev
        password: 123456
      client:
        serviceUrl:
          defaultZone: http://${eureka.auth.user}:${eureka.auth.password}@localhost:7001/eureka/
      instance:
        #使用IP进行注册
        prefer-ip-address: true
        #配置实例的注册ID
        instance-id: ${spring.cloud.client.ip-address}:${server.port}
        #心跳时间,即服务续约间隔时间(缺省为30s)
        lease-renewal-interval-in-seconds: 5
        #发呆时间,即服务续约到期时间(缺省为90s)
        lease-expiration-duration-in-seconds: 10
        health-check-url-path: /actuator/health
    server:
      port: 7002
    spring:
      application:
        name: eureka-client

    4. eureka-ribbon-client

     新建该项目主要用于测试zuul网关路由到eureka-ribbon-client

       4.1 pom.xml 

        

      <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.1.8.RELEASE</version>
            </dependency>

         4.2 启动类

            

    package com.devin.eurekaribbonclient;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @EnableEurekaClient
    @SpringBootApplication
    public class EurekaRibbonClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaRibbonClientApplication.class, args);
        }
    
    }
    

      

              4.3 RibbonConfig

            

    package com.devin.eurekaribbonclient.config;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * @author Devin Zhang
     * @className RibbonConfig
     * @description TODO
     * @date 2020/3/31 10:48
     */
    @Configuration
    public class RibbonConfig {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    

      

         4.4  service 通过RestTemplate去负载均衡调用eureka-client

          

    package com.devin.eurekaribbonclient.service;
    
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import javax.annotation.Resource;
    
    /**
     * @author Devin Zhang
     * @className HelloService
     * @description TODO
     * @date 2020/3/31 10:50
     */
    
    @Service
    public class HelloService {
    
        @Resource
        private RestTemplate restTemplate;
    
        public String sayHello(String name) {
            return restTemplate.getForObject("http://eureka-client/sayHello?name=" + name, String.class);
        }
    }
    

        4.5 controller  

         

    package com.devin.eurekaribbonclient.controller;
    
    import com.devin.eurekaribbonclient.service.HelloService;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    
    /**
     * @author Devin Zhang
     * @className RibbonHelloController
     * @description TODO
     * @date 2020/3/31 10:50
     */
    @RestController
    public class RibbonHelloController {
    
        @Resource
        private HelloService helloService;
    
        @GetMapping("/sayHelloFromRibbon")
        public String sayHelloFromRibbon(String name) {
            return helloService.sayHello(name);
        }
    
    }
    

      

     4.6 application.yml配置类

       eureka-ribbon-client的穷端口为7004 

       

    eureka:
      auth:
        user: dev
        password: 123456
      client:
        serviceUrl:
          defaultZone: http://${eureka.auth.user}:${eureka.auth.password}@localhost:7001/eureka/
      instance:
        #使用IP进行注册
        prefer-ip-address: true
        #配置实例的注册ID
        instance-id: ${spring.cloud.client.ip-address}:${server.port}
        #心跳时间,即服务续约间隔时间(缺省为30s)
        lease-renewal-interval-in-seconds: 5
        #发呆时间,即服务续约到期时间(缺省为90s)
        lease-expiration-duration-in-seconds: 10
        health-check-url-path: /actuator/health
    server:
      port: 7004
    spring:
      application:
        name: eureka-ribbon-client

      5. eureka-zuul-client

         在eureka-zuul-client中定义了 熔断器,过滤器,以及路由的配置

         5.1 pom.yml

        

     <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.1.8.RELEASE</version>
            </dependency>

        5.2 启动类

        

    package com.devin.eurekazuulclient;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
    
    @EnableEurekaClient
    @EnableZuulProxy
    @SpringBootApplication
    public class EurekaZuulClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaZuulClientApplication.class, args);
        }
    
    }
    

     

       5.3 定义熔断器处理类,当通过zuul访问的服务不可用时,就进入熔断器方法

       

    package com.devin.eurekazuulclient.service;
    
    import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.client.ClientHttpResponse;
    import org.springframework.stereotype.Component;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * @author Devin Zhang
     * @className BaseZuulFallbackProvider
     * @description TODO
     * @date 2020/3/31 11:05
     */
    @Component
    public class BaseZuulFallbackProvider implements FallbackProvider {
        @Override
        public String getRoute() {
            //返回的为服务的名称,如果所有client都走这个熔断器的话则返回*
            return "*";
        }
    
        @Override
        public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
            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("sorry, the system is busy now ,pls try later ,response by zuul hystrix".getBytes());
                }
    
                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.APPLICATION_JSON);
                    return headers;
                }
            };
        }
    }
    

     

        5.4 定义filter,用于统一的权限校验等

        比如我们做简单的token不能为空校验

         

    package com.devin.eurekazuulclient.filter;
    
    
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import com.netflix.zuul.exception.ZuulException;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    
    
    import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
    
    /**
     * @author Devin Zhang
     * @className ZuulBaseFilter
     * @description TODO
     * @date 2020/3/31 11:18
     */
    @Component
    public class ZuulBaseFilter extends ZuulFilter {
    
        @Override
        public String filterType() {
            return 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();
            String token = request.getParameter("token");
            if (token == null) {
                try {
                    currentContext.setSendZuulResponse(false);
                    currentContext.setResponseStatusCode(301);
                    currentContext.getResponse().getWriter().write("token is empty!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }
    

      

      5.5 application.yml配置路由映射

        /zuulapi/ 的请求将被路由到eureka-client 服务

       /ribbonapi/ 的请求将被路由到 eureka-ribbon-client 服务

        

    eureka:
      auth:
        user: dev
        password: 123456
      client:
        serviceUrl:
          defaultZone: http://${eureka.auth.user}:${eureka.auth.password}@localhost:7001/eureka/
      instance:
        #使用IP进行注册
        prefer-ip-address: true
        #配置实例的注册ID
        instance-id: ${spring.cloud.client.ip-address}:${server.port}
        #心跳时间,即服务续约间隔时间(缺省为30s)
        lease-renewal-interval-in-seconds: 5
        #发呆时间,即服务续约到期时间(缺省为90s)
        lease-expiration-duration-in-seconds: 10
        health-check-url-path: /actuator/health
    server:
      port: 8000
    spring:
      application:
        name: zuul-client
    zuul:
      routes:
        zuulapi:
          path: /zuulapi/**
          serviceId: eureka-client
        ribbonapi:
          path: /ribbonapi/**
          serviceId: eureka-ribbon-client

      6. 测试

      启动eureka-server  7001

      启动eureka-client  7002 7003 

      java -jar eureka-client-0.0.1-SNAPSHOT.jar --server.port=7002

      java -jar eureka-client-0.0.1-SNAPSHOT.jar --server.port=7003

      启动eureka-ribbon-client 7004

      启动eureka-zuul-client  8000

      启动后的注册信息如下 http://localhost:7001/

      

      6.1 路由转发校验 

        分别访问

       http://localhost:8000/zuulapi/sayHello?name=devin&token=123

       http://localhost:8000/ribbonapi/sayHelloFromRibbon?name=devin&token=123

       可以看到已经路由到eureka-client 和 eureka-ribbon-client的接口

      6.2 token验证

     访问  http://localhost:8000/zuulapi/sayHello?name=devin 可以看到会提示token为空

     

     访问  http://localhost:8000/zuulapi/sayHello?name=devin&token=123 可以看到访问正常,

      说明请求已经被转发到eureka-client同时过滤器校验也已经通过,并且在7002和7003之间进行切换

     从访问结果可以看出,zuul自动在eureka-client之间进行了负载均衡

     

      同样访问 http://localhost:8000/ribbonapi/sayHelloFromRibbon?name=devin&token=123 也能得到同样的结果

     6.3 zuul熔断器验证

       分别停掉两台eureka-client,然后分别访问如下地址,可以看到zuul的熔断器已经生效

       http://localhost:8000/zuulapi/sayHello?name=devin&token=123

       http://localhost:8000/ribbonapi/sayHelloFromRibbon?name=devin&token=123

       

     

    至此,Zuul网关搭建并验证完毕

     

       

  • 相关阅读:
    POJ 1611 : The Suspects (普通并查集)
    深入解析 Dubbo 3.0 服务端暴露全流程
    智能搜索推荐一体化营收增长解决方案
    云上应用系统数据存储架构演进
    EMR on ACK 全新发布,助力企业高效构建大数据平台
    介绍一下闭包和闭包常用场景?
    BFC
    高斯消元学习笔记
    云虚拟主机如何设置域名解析
    Centos7.3安装openJDK
  • 原文地址:https://www.cnblogs.com/DevinZhang1990/p/12604589.html
Copyright © 2011-2022 走看看