首页 > 经验记录 > 微服务路由解决方案: "Zuul" 服务搭建;以及自定义Zuul过滤器的代码编写。

微服务路由解决方案: "Zuul" 服务搭建;以及自定义Zuul过滤器的代码编写。

 
微服务架构有一个问题,那就是客户端如何访问各个微服务。
总不能在客户端APP/HTML写很多个不同的地址来请求吧?这样维护及其困难、开发不易。
这时候就需要一个网关,客户端的请求都发给这个网关, 然后由他来给你路由到别的微服务里边。
netflix 就开源了一个微服务网关:Zuul ,可以和 SpringCloudNetflix 全家桶(Eureka、Ribbon、Hystrix等)完美集成。
 
废话不多说.代码撸起来。
首先,项目创建,当然,创建的还是我那个Gradle搭的SpringCloudFinchley项目的子模块。
这回不用加什么依赖,只需要一个Zuul的依赖和Eureka Client的依赖就够了。
而且Zuul自己本身就集成了Ribbon和Hystrix,非常强大。
build.gradle:

dependencies {
    compile("org.springframework.cloud:spring-cloud-starter-netflix-zuul")
    compile("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
//    compile("org.springframework.cloud:spring-cloud-starter-netflix-ribbon")
//    compile("org.springframework.cloud:spring-cloud-starter-netflix-hystrix")
}

 
然后在Application启动类上边加上@EnableZuulProxy 用以声明zuul代理
最主要的: 配置类yml文件
既然这个 zuul 是提供一个服务路由的功能,又已知 zuul 完美的集成了 Eureka。可以从Eureka Server中得到所有注册进去的服务。
那么,最需要进行配置的。自然是访问路径所对应的服务啦, 在zuul这个服务的配置文件里,专门有个地方给你写这个路由规则( zuul.routes )
我的配置文件:

server:
  port: 8060
spring:
  application:
    name: sc-demo-microservice-zuul #这个名字会注册到 Eureka 里去
#Actuato 配置
management:
  endpoint:
# 暴露shutdown功能
#    shutdown:
#      enabled: true
  endpoints:
    web:
      exposure:
        include: '*'  #暴露哪些端点
        exclude:      #隐藏哪些端点
#Eureka client端配置
eureka:
  client:
    service-url:
        defaultZone: http://user:614@localhost:8080/eureka/,http://user:614@localhost:8081/eureka/
  instance:
    prefer-ip-address: true #将自己ip注册到Eureka Server
zuul:
  ribbon-isolation-strategy: thread #hystrix隔离策略改为线程 (默认是信号量
  thread-pool:
      use-separate-thread-pools: true #让每个路由使用它独立的线程池
      thread-pool-key-prefix: myprefix- #前缀
  routes: #路由配置
    local-router:
      url: local/test #本地转发
      path: forward:/local/test
    aggregate-router:
      url: aggregate/**
      path: forward:/aggregate/**
    user-router:
      sensitive-headers: Cookie,Set-Cookie,Authorization  #指定敏感header
      service-id: sc-demo-microservice-user
      path: /zuul_user/**
    movie-router:
      service-id: sc-demo-microservice-movie
      path: /zuul_movie/**
  #  ignored-services 指定微服务忽略它,不对它进行路由,使用"*" 忽略所有,只路由指定了的
  ignored-services: sc-demo-microservice-eureka_1,sc-demo-microservice-eureka_2

 
虽然我这个配置文件里注释已经写得挺详细了,但还是简单的解释一下:
zuul.routes 这个属性树下面第一级节点,即我写的local-router、user-router 等,这一级只是让你写个路由规则的名字。 瞎写就行。
再下一级,大致可以分为两种:
1、路由到其余微服务的 指定好 service-id(即服务注册进Eureka的服务名) 和对应的访问路径就行了 ( 例如: 我用户微服务有个API请求路径是 user/{id},我现在就可以通过 ZUUL_ADDRESS:ZUUL_PORT/zuul_user/user/{id} 来访问我sc-demo-microservice-user中的API)。
 2、路由到本地由Zuul自己进行处理的 指定好客户端访问路径,和对应的本地API地址( forward: +本地API的地址) 就行
 

到这步,其实Zuul这个服务就搭建完毕了, 已经可以使用了。而且,不但可以帮你进行服务路由,还会用自带的Ribbon给你的请求进行负载均衡。

 
搭建完了,当然还不够,还能让这个 zuul 服务更加强大
zuul的路由功能是基于他自己编写的一大堆过滤器实现的,这里先简单说下他的过滤器类型

他主要有四大标准过滤器类型,这四种是最主要的

1、PRE  在请求被路由之前调用这个过滤器
2、ROUTING 这个过滤器将请求路由到微服务
3、POST 这个过滤器在路由到对应微服务之后再执行
4、ERROR 出错时进的
 
zuul 他自己有这几个过滤器的实现,当然,他写的我不动他,我可以自己额外写过滤器来实现自己的功能嘛。
zuul过滤器的实现非常简单,只要继承 ZuulFilter 这个类就完事了。
我写了个日志记录的过滤器:

package com.skypyb.sc.config;
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.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;
@Configuration
public class ZuulFilterConfig {
    /**
     * 用起这个过滤器来
     * @return
     */
    @Bean
    public PreRequestLogFilter preRequestLogFilter() {
        return new PreRequestLogFilter();
    }
    /**
     * 请求在路由之前的过滤器
     */
    public class PreRequestLogFilter extends ZuulFilter {
        private Logger logger = LoggerFactory.getLogger(PreRequestLogFilter.class);
        @Override
        public String filterType() {
            return FilterConstants.PRE_TYPE;
        }
        @Override
        public int filterOrder() {
            return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
        }
        @Override
        public boolean shouldFilter() {
            return true;
        }
        @Override
        public Object run() throws ZuulException {
            RequestContext ctx = RequestContext.getCurrentContext();
            HttpServletRequest request = ctx.getRequest();
            logger.info("send {} request to {}.", request.getMethod(), request.getRequestURI());
            return null;
        }
    }//internal class end...
}

这几个方法不多说,看下ZuulFilter源码的注释就知道具体是什么意思了。反正就是关于你写的过滤器的设置(类型、执行顺序、是否执行、具体逻辑)
我这过滤器很简单,就记录一下请求方法、地址,是个PRE类型的过滤器,会在路由之前调用。过滤器能干的事情很多,认证啊、加密啊啥的都行,看业务需求了。
 
 

           


CAPTCHAis initialing...

2 COMMENTS

EA PLAYER &

历史记录 [ 注意:部分数据仅限于当前浏览器 ]清空

      00:00/00:00