springcloud——zuul

Zuul默认使用的HTTP客户端是Apache HTTPClient,主要功能是路由转发过滤器。zuul的核心是一系列的filters, 类似于java Servlet框架的Filter,或者AOP。zuul把请求路由到用户处理逻辑的过程中,这些filter参与一些过滤处理,比如Authentication;外围系统或者用户通过网关访问服务,网关通过注册中心找到对应提供服务的客户端(Ribbon获取服务),网关也需要到注册中心进行注册。

Zuul可以为同一注册中心中的其他服务的访问做反向代理(配置serviceId属性),也可以为外部服务访问做代理(配置URL属性),还可以对zuul服务本身的接口做代理(配置URL属性的值为forward关键字加路径)

搭建Zuul网关服务实现路由和过滤

1.引入Zuul依赖

<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>

 2.在启动类上添加@EnableZuulProxy注解


@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}

3.自定义配置zuul服务的路由 (zuul默认以服务ID作为路由配置)

zuul默认情况下会以注册中心中的服务id作为路由设置,即如果请求是注册中心中的某个serviceId组成的URL就路由给对应的服务;zuul中的服务列表使用的是Ribbon实现的;

了解下zuul节点下的配置属性

      zuul.prefix:api          配置在zuul节点下的属性,值为api 表示为所有URL加一个前缀

      zuul.ignoredServices:"*"       表示禁用默认的路由配置,值为*表示禁用所有默认的路由,出去下面routes节点下配置的            路由外其他都无效。此属性也可以禁用特定的某个或多个默认的服务ID路由,多个服务ID用逗号隔开。

      zuul.routes:       这个节点是路由配置开始的节点,其下可以定义多个配置组

      zuul.routes.path:  指的是用户访问的URL

      zuul.routes.serviceId  / zuul.routes.url:   路由目标服务在Eureka中的服务实例ID或者服务的url地址

在目标服务集成Eureka的情况下自定义路由(目标服务使用serviceId配置)

routes节点后配置路由,,。

当然,目标服务也可以使用URL代替serviceId,只不过这种情况下要实现负载访问就要禁用Eureka的Ribbon,然以单独配置Ribbon并执行负载的多个服务ID,这种方式感觉并没有什么用。。。。

如下示例配置了两组路由,一组是customerURL,第二组是userURL。配置里有prefix前缀属性为api,所以第一组配置就是把用户访问地址以api/customer/*的请求路由到customer-service这个服务中;第二组配置就是把api/user/*的请求路由到user-service这个服务中。

server:
  port: 8040
spring:
  application:
    name: zuul
# 配置Eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
# 构建路由地址
zuul:
    #所有URL都要加api这个前缀
  prefix:api          
  # 禁用默认的路由设置,使用此配置以后只有下面配置的两组路由才会生效
  ignoredServices:"*"
  routes:
    # 这里可以自定义,只是一个唯一的标识
    customerURL:
      # 匹配的路由规则
      path: /customer/**
      # 路由的目标服务名
      serviceId: customer-service
    userURL:
      # 匹配的路由规则
      path: /user/**
      # 路由的目标服务名
      serviceId: user-service

上面这种配置中,如果某个服务有多个实例,以Eureka中集成Ribbon负载方式进行访问;如果使用URL配置目标服务的路由,就要单独配置Ribbon来实现负载:

server:
  port: 8080
spring:
  application:
    name: zuul
# 配置eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
# 构建路由地址
zuul:
  routes:
    # 这里可以自定义
    demo2:
      # 匹配的路由规则
      path: /demo/**
      # 使用URL配置,不适用服务ID
      url: http://127.0.0.1:8070
# 关闭使用eureka负载路由
ribbon:
  eureka:
    enabled: false
# 如果不使用eureka的话,需要自己定义路由的那个服务的其他负载服务
demo:
  ribbon:
    # 这里写你要路由的demo服务的所有负载服务请求地址,本项目只启动一个,因此只写一个
    listOfServers: http://localhost:8090/

对于path属性的配置,要符合ant样式:

            user/*         这个配置只对user/id这种/后一个值得url生效

             user/**      这个配置可以以user/开头,任意个值得url生效。 

不使用Eureka的情况下自定义配置路由(配置URL属性代替serviceId,无负载均衡)

由于没有Eureka注册中心,也就没有服务ID,只能使用URL地址配置服务的路由地址。

server:
  port: 8080
spring:
  application:
    name: zuul
# 构建路由地址
zuul:
  routes:
    # 这里可以自定义
    demo2:
      # 匹配的路由规则
      path: /demo/**
      # 路由的目标地址
      url: http://localhost:8090/

4.Zuul过滤器配置 

 默认情况下,Spring Cloud Zuul在请求路由时,会过滤掉请求头信息中的 一些敏感信息,防止它们被传递到下游的外部服务器。

zuul定义了四种标准过滤器类型,这四种过滤器分别对应着请求的生命周期

  • pre:路由请求前过滤。

  • post:路由请求后(此时已经走完目标服务程序了)过滤。

  • route:路由请求时过滤。

  • error:当上述三种过滤器抛出异常时,会走error过滤。

自定义并使用Zuul Filter

自定义过滤器很简单,只要继承ZuulFilter类并重写相应的方法,用@Component注解作为spring的bean使用即可。

ZuulFilter类提供了如下方法方便我们自定义和实现一个Zuul过滤器:

    public String filterType():设置这个过滤器的类型是

    public int filterOrder() :设置过滤器的优先级,多个同类型(filterType)ZuulFilter中哪个filter的此方法返回值最小优先级最高

    public boolean shouldFilter() :决定此过滤器是否生效,返回true表示生效
 
    public Object run() :过滤器的逻辑执行方法,在这个方法内调用doFiltrate方法

    private boolean doFiltrate (HttpServletRequest request) :过滤逻辑,返回是否通过过滤(true或false)

下面是自定义一个pre类型的ZuulFilter的示例代码:

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.util.RequestBodyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
 
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Random;
 

@Component
public class PreFilter extends ZuulFilter {
 
    /**
     * 定义过滤类型
     *  【pre】路由请求前被调用过滤、
     *  【post】后置过滤、
     *  【error】错误过滤、
     *  【route】路由请求时被调用
     */
    @Override
    public String filterType() {
        // 设置这个过滤器的类型是 前置过滤器
        return "pre";
    }
 
    /**
     * 设置过滤器的优先级,如果服务中有多个同类型(filterType)的ZuulFilter
     *
     * 这个方法的值越小代表越先过滤
     */
    @Override
    public int filterOrder() {
        return 0;
    }
 
    /**
     * 决定此过滤器是否生效,返回true表示生效
     */
    @Override
    public boolean shouldFilter() {
       return true;
    }
 
    /**
     * 过滤器的逻辑执行方法,在这个方法内调用doFiltrate方法
     *
     * 注:当RequestContext.setSendZuulResponse(false);时表示过滤失败,zuul不对其进行路由
     */
    @Override
    public Object run() {
        // 获取请求上下文
        RequestContext requestContext = RequestContext.getCurrentContext();
 
        // 获取请求
        HttpServletRequest request = requestContext.getRequest();
        if (doFiltrate(request)) {
            // 验证通过
            return null;
        }
        // 如果验证不通过,那么过滤该请求,不往下级服务去转发请求,到此结束
        requestContext.setSendZuulResponse(false);
        requestContext.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
        requestContext.setResponseBody(HttpStatus.FORBIDDEN.getReasonPhrase());
        requestContext.getResponse().setContentType("text/html;charset=UTF-8");
        return null;
    }
    
    /**
     * 执行过滤逻辑,返回是否通过过滤结果
     */
    private boolean doFiltrate (HttpServletRequest request) {
        try {
            /// 获取请求头
            String who = request.getHeader("Authorization");
            log.info(" requestHeader param 【Authorization】 is -> {} !", who);
 
            /// 向请求头中添加信息
            // requestContext.addZuulRequestHeader("");
 
            // 获取请求体
            RequestBodyUtil requestBodyUtil = new RequestBodyUtil(request);
            String requestBody = requestBodyUtil.getBody();
            log.info(" got requestBady -> {}", requestBody);
 
            // TODO 由于是测试代码,这里随机返回 成功、失败
            return new Random().nextBoolean();
        } catch (Exception e) {
            log.error(" zull authe occur error !", e);
            return false;
        }
    }
}

禁用Zuul中默认启用的过滤器 

上面提到了我们自己定义的filter如果不需要使用可以通过shouldFilter方法返回false实现对这个过滤器是禁用。但是Zuul默认启用了一些filter的bean,如果我们不想使用显然没办法通过修改方法来实现,这个时候我们可以通过配置yml来实现:

直接在配置文件中:zuul.<filtername>.<filtertype>.disable=true

例如:

zuul:
  DebugFilter:
    pre:
      disable: true

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WannaRunning

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值