• SpringCloud的学习记录(7)


    这一章节讲zuul的使用.

    在我们生成的Demo项目上右键点击New->Module->spring Initializr, 然后next, 填写Group和Artifact等信息,

    这里Artifact填写eurekazuul, 再次next, 选择内容如下的pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.3.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.xum</groupId>
        <artifactId>eureka-zuul</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>eureka-zuul</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
        <repositories>
            <repository>
                <id>spring-milestones</id>
                <name>Spring Milestones</name>
                <url>https://repo.spring.io/milestone</url>
            </repository>
        </repositories>
    
    </project>

    eureka-zuul模型结构如下:

    image

    1. 首先是EurekaZuulApplication.java内容如下:

    package com.xum.eurekazuul;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
    import org.springframework.cloud.netflix.turbine.EnableTurbine;
    import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
    
    @SpringBootApplication
    @EnableZuulProxy  // 这里是启用zuul路由的注解
    @EnableHystrixDashboard
    @EnableTurbine
    public class EurekaZuulApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaZuulApplication.class, args);
        }
    
    }

    2. application.yml内容如下:

    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    server:
      port: 8773
    zuul:   // 这里定义了两个api接口的路由, 一个指向ribbon-consumer, 一个指向fegin-client
      routes:
        api-a:
          path: /api-a/**
          serviceId: ribbon-consumer
        api-b:
          path: /api-b/**
          serviceId: fegin-client
    turbine:
      aggregator:
        cluster-config: default
      app-config: '*'
      cluster-name-expression: new String("default")
    spring:
      application:
        name: eureka-zuul
    management:
      endpoint:
        health:
          show-details: always
      endpoints:
        web:
          exposure:
            include: '*'

    3. 然后是PermissionsFilter.java内容如下:

    package com.xum.eurekazuul.filter;
    
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import com.netflix.zuul.exception.ZuulException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    
    import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
    
    @Component
    public class PermissionsFilter extends ZuulFilter {
    
        private static final Logger LOG = LoggerFactory.getLogger(PermissionsFilter.class);
    
        @Override
        public String filterType() {
            return PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return 0;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
            /*RequestContext ctx = RequestContext.getCurrentContext();
            return (boolean) ctx.get("isSuccess");*/
        }
    
        @Override
        public Object run() throws ZuulException {
            RequestContext ctx = RequestContext.getCurrentContext();
            HttpServletRequest request = ctx.getRequest();
    
            LOG.info(String.format("%s AccessNameFilter request to %s", request.getMethod(), request.getRequestURL().toString()));
            String name = request.getParameter("name");// 获取请求的参数
            if(null != name && "xum".equalsIgnoreCase(name)) { // 在向eureka-client项目里调用api的时候,检查带的name内容是否是xum 
                ctx.setSendZuulResponse(true);
                ctx.setResponseStatusCode(200);
                ctx.set("isSuccess", true);
                return null;
            }else{
                ctx.setSendZuulResponse(false);
                ctx.setResponseStatusCode(401);
                ctx.setResponseBody("{"result":"name is not correct!"}");
                ctx.set("isSuccess", false);
                return null;
            }
        }
    }

    4. 其次就是ApiFallbackProvider.java内容如下:

    package com.xum.eurekazuul.provider;
    
    import com.netflix.hystrix.exception.HystrixTimeoutException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    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;
    
    @Component
    public class ApiFallbackProvider implements FallbackProvider {
    
        private static final Logger LOG = LoggerFactory.getLogger(ApiFallbackProvider.class);
    
        @Override
        public String getRoute() {
            LOG.info("ApiFallbackProvider=>getRoute");
            return "*";
        }
    
        @Override
        public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
            LOG.info(String.format("route:%s,exceptionType:%s,stackTrace:%s", route, cause.getClass().getName(), cause.getStackTrace()));
            String message = "";
            if (cause instanceof HystrixTimeoutException) {
                message = "Timeout";
            } else {
                message = "Service exception";
            }
            return fallbackResponse(message);
        }
    
        public ClientHttpResponse fallbackResponse(String message) {
    
            return new ClientHttpResponse() {
                @Override
                public HttpStatus getStatusCode() throws IOException {
                    LOG.info("ApiFallbackProvider=>ClientHttpResponse=>getStatusCode");
                    return HttpStatus.OK;
                }
    
                @Override
                public int getRawStatusCode() throws IOException {
                    LOG.info("ApiFallbackProvider=>ClientHttpResponse=>getRawStatusCode");
                    return 200;
                }
    
                @Override
                public String getStatusText() throws IOException {
                    LOG.info("ApiFallbackProvider=>ClientHttpResponse=>getStatusText");
                    return "OK";
                }
    
                @Override
                public void close() {
                    LOG.info("ApiFallbackProvider=>ClientHttpResponse=>close");
                }
    
                @Override
                public InputStream getBody() throws IOException {
                    LOG.info("ApiFallbackProvider=>ClientHttpResponse=>getBody");
                    String bodyText = String.format("{"code": 999,"message": "Service unavailable:%s"}", message);
                    return new ByteArrayInputStream(bodyText.getBytes());
                }
    
                @Override
                public HttpHeaders getHeaders() {
                    LOG.info("ApiFallbackProvider=>ClientHttpResponse=>getHeaders");
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.APPLICATION_JSON);
                    return headers;
                }
            };
        }
    }

    顺序启动一下项目:

    image

    1. eureka-server

    2. config-server

    3. eureka-client

    4. fegin-client

    5. ribbon-consumer

    6. zuul-client

    然后再浏览器或则post man中输入http://localhost:8773/api-a/ribbonconsumer/test?name=xum, 显示内容如下:

    image

    在eureka-zuul项目里Event log打印出如下类似的log:

    2019-03-31 14:52:51.881  INFO 1976 --- [nio-8773-exec-9] c.x.eurekazuul.filter.PermissionsFilter  : POST AccessNameFilter request to http://localhost:8773/api-a/ribbonconsumer/test

    当输入http://localhost:8773/api-a/ribbonconsumer/test, 不带任何参数的时候, 显示内容如下, 路由网关提示name不正确.

    image

    然后再post man中输入http://localhost:8773/api-b/feign/feignconsumer?name=xum, 内容如下:

    image

    也能在eureka-client项目的Event log里看到如下类似的log:

    2019-03-31 14:58:27.395  INFO 1976 --- [nio-8773-exec-5] c.x.eurekazuul.filter.PermissionsFilter  : POST AccessNameFilter request to http://localhost:8773/api-b/feign/feignconsumer

    相同的道理, 如果参数没有name或则name只不对, 路由网关都会提示出错.

    当eureka-client项目没有启动的时候, Hyrtrix会进行相应自我保护.

  • 相关阅读:
    Chroot 特性 ?
    服务端处理 Watcher 实现 ?
    四种类型的数据节点 Znode ?
    Zookeeper 文件系统 ?
    ZooKeeper 面试题?
    Mapper 编写有哪几种方式?
    Mybatis 的一级、二级缓存?
    Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
    一对一、一对多的关联查询 ?
    Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?
  • 原文地址:https://www.cnblogs.com/xumBlog/p/10631425.html
Copyright © 2020-2023  润新知