SpringCloud Zuul

1.微服务网关简介

在微服务环境下,不同的服务有其不同的网络地址,若让客户端直接与各个微服务通信,客户端会多次请求不同微服务,存在跨域请求,处理相对复杂。此时我们就需要使用微服务网关。微服务网关介于服务端与客户端的中间层,所有外部服务请求都会先经过微服务网关,客户只能跟微服务网关进行交互,无需调用特定微服务接口,使得开发得到简化。

2.Zuul简介

Zuul 是开源的微服务网关,可与 Eureka、Ribbon、Hystrix 等组件配合使用,Zuul 它的核心是一系列过滤器,这些过滤器可完成下面功能:

  • 身份认证与安全:识别每个资源的验证要求,并拒绝那些要求不符合的请求
  • 审核与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图
  • 动态路由:动态的将请求路由到不同的后端集群
  • 压力测试:逐渐增加指向集群的流量,以了解性能
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
  • 静态响应处理:在边缘位置直接建立部分响应,从而避免转发到内部集群
  • 多区域弹性:跨越 AWS Region 进行请求路由,实现 ELB 使用多样化,让系统边缘更贴近使用者

3.配置

Maven

引入spring-cloud-starter-netflix-eureka-clientspring-cloud-starter-netflix-zuul

        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-zuul
        

添加注解

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

最后记得将他注册到注册中心上,就可以直接运行了,是不是非常简单呢?

4.详细配置

  • 在配置文件中加入management.endpoints.web.exposure.include=*可以通过访问actuator/routes来查看路由情况。
  • 配置需要路由的路径和忽略的路径。配置路由格式为【 服务名称:路径 】,假如要配置product服务:
  routes:
    product: /myProduct/**
  ignored-patterns:
   - /**/product/**
  • 跨域
    假如服务中单个接口需要跨域,只要在方法上添加@CrossOrigin(allowCredentials = "true")注解。
    假如需要对多个接口做跨域,可以在Zuul中做配置。
/**
 * 跨域配置
 *
 * @author BaoZhou
 * @date 2018/9/13
 */
@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();


        config.setAllowCredentials(true);
        //可以写域名,比如http://www.baidu.com
        config.setAllowedOrigins(Arrays.asList("*"));
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setAllowedMethods(Arrays.asList("GET","POST"));
        config.setMaxAge(300L);
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter();
    }
}
  • 默认经过路由不转发cookie等信息,我们可以在配置文件中加sensitiveHeaders来开启
zuul:
  routes:
    product: /myProduct/**
  ignored-patterns:
     - /**/product/**
  sensitiveHeaders:
  • 配合SpringBus动态配置Zuul。需要添加配置项
 @ConfigurationProperties("zuul")
    @RefreshScope
    public ZuulProperties zuulProperties() {
        return new ZuulProperties();
    }

Zuul有四种过滤器:

  • PRE:在请求被路由之前调用,可用于身份验证、集群中选择请求的微服务、记录调试信息等,可以用于限流,鉴权,参数校验调整,请求转发。
  • ROUTING:请求路由到微服务时执行,用于构建发送给微服务的请求,使用 HttpClient 或 Ribbon 请求微服务。
  • POST:在路由到微服务后执行,可用来为响应添加 Header,收集统计信息和指标、将相应从微服务发送给客户端等,可以用于统计,日志等。
  • ERROR:在其他阶段发生错误时执行该过滤器。

限流 令牌桶

public class RateLimitFilter extends ZuulFilter {
    private static final RateLimiter RATE_LIMITER =RateLimiter.create(100);
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return SERVLET_DETECTION_FILTER_ORDER - 1;
    }

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

    @Override
    public Object run() throws ZuulException {
        if(!RATE_LIMITER.tryAcquire())
        {
            throw new RateLimitException();
        }
        return null;
    }
}

添加请求头

public class AddResponseHeaderFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return SEND_RESPONSE_FILTER_ORDER - 1;
    }

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

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletResponse response = requestContext.getResponse();
        response.setHeader("X-Foo",UUID.randomUUID().toString());
        return null;
    }
}

校验请求参数

public class TokenFilter extends ZuulFilter {

    /**
     * 指定过滤器类型
     * 可以从常量中去选取
     * 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";
     *
     * @return
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 设置过滤器优先级,数字越小优先级越高
     * public static final int DEBUG_FILTER_ORDER = 1;
     * public static final int FORM_BODY_WRAPPER_FILTER_ORDER = -1;
     * public static final int PRE_DECORATION_FILTER_ORDER = 5;
     * public static final int RIBBON_ROUTING_FILTER_ORDER = 10;
     * public static final int SEND_ERROR_FILTER_ORDER = 0;
     * public static final int SEND_FORWARD_FILTER_ORDER = 500;
     * public static final int SEND_RESPONSE_FILTER_ORDER = 1000;
     * public static final int SIMPLE_HOST_ROUTING_FILTER_ORDER = 100;
     * public static final int SERVLET_30_WRAPPER_FILTER_ORDER = -2;
     * public static final int SERVLET_DETECTION_FILTER_ORDER = -3;
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }

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

    /**
     * 处理逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        //从Url参数里获取token,也可以从cookie,header里获取
        String token = request.getParameter("token");
        if(StringUtils.isEmpty(token))
        {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

一般在run里写逻辑,shouldFilter里写是否需要过滤来保证逻辑的清晰。

文中很多内容引用自https://www.jianshu.com/p/29e9c91e3f3e,特别感谢!

你可能感兴趣的:(SpringCloud Zuul)