springcloud笔记7——服务网关Zuul

Zuul服务网关介绍

Zuul 主要提供了对请求的路由与过滤功能。

  • 路由:将外部请求转发到具体的微服务实例上,是外部访问微服务的统一入口。
  • 过滤:对请求的处理过程进行干预,对请求进行校验、 鉴权等处理。
    在这里插入图片描述

搭建网关项目

1,创建springboot工程,导入依赖

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <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-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </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>

2,启动类添加注解

//开启zuul代理模式
@EnableZuulProxy

3,修改配置文件

server:
  port: 8090

spring:
  application:
    name: zuulservice

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8000/eureka

到这里,一个网关服务就可以启动了,网关服务从eureka获取服务列表,用户访问所有服务都走网关:http://127.0.0.1:8090/微服务名称/请求路径

比如 http://127.0.0.1:8090/consumer-depart/consumer/depart/list

配置网关路由

zuul:
  routes:
    #自定义路径来替代微服务名称 比如 http://127.0.0.1:8090/con/consumer/depart/list
    #配置路由规则
    # /**  匹配任意多级路径    /abc8080/xxx/ooo/jjj
    # /*   仅可匹配一级路径    /abc8080/xxx
    # /?   仅可匹配一级路径,但该路径只能是一个字符    /abc8080/x
    consumer-depart: /con/**

  #配置路径前辍 http://127.0.0.1:8090/abc/con/consumer/depart/list
  prefix: /abc

  #屏蔽通过指定微服务名称访问
  # ignored-services: consumer-depart
  #屏蔽所有微服务名称访问
  ignored-services: "*"
  
  #屏蔽指定路径
  ignored-patterns: /**/list/**

  #默认情况下,Cookie、Set-Cookie、Authorization 敏感请求头信息会被 zuul 屏蔽掉
  #屏蔽指定的请求头,设置值替换原有屏蔽的三个信息,多个以逗号分隔或者["",""]
  sensitive-headers: Authorization

负载均衡策略

Zuul内置有ribbon,在网关配置负载均衡策略,可以yml配置或者代码里

    // 设置负载均衡算法为"随机算法"
    @Bean
    public IRule loadBalanceRule() {
        return new RandomRule();
    }

服务降级

/**
 * zuul的服务降级类
 */
@Component
public class ConsumerFallback implements FallbackProvider {

    // 指定要进行服务降级的消费者微服务名称
    @Override
    public String getRoute() {
        // 对所有微服务开启降级功能
        return "*";
        // 仅对指定的微服务进行降级
        // return "abcmsc-consumer-depart-8080";
    }

    /**
     *   定义降级响应
     * @param route  指当前正在处理的微服务名称
     * @param cause
     * @return
     */
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        // 对"abcmsc-consumer-depart-8080"不进行服务降级
        if("abcmsc-consumer-depart-8080".equals(route)) return null;

        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                // 返回状态常量
                return HttpStatus.SERVICE_UNAVAILABLE;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                // 返回状态码,这里为503
                return HttpStatus.SERVICE_UNAVAILABLE.value();
            }

            @Override
            public String getStatusText() throws IOException {
                // 返回状态短语,这里为Service Unavailable
                return HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase();
            }

            // 关闭当前的Response
            @Override
            public void close() { }

            // 定义响应体
            @Override
            public InputStream getBody() throws IOException {
                // 指定降级信息
                String msg = "fallback:" + route;
                return new ByteArrayInputStream(msg.getBytes());
            }

            // 定制响应头
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

配置网关过滤

/**
 * zuul过滤器,/con 服务必须有token请求头
 */
@Component
@Slf4j
public class RouteFilter extends ZuulFilter {

    // 设置过滤类型
    @Override
    public String filterType() {
        // 指定在路由之前进行过滤
        return FilterConstants.PRE_TYPE;
    }

    // 设置当前过滤器在所有过滤器中执行的顺序
    // 数字越小优先级越高,可以是负数
    @Override
    public int filterOrder() {
        return -5;
    }

    // 通过过滤后要执行的业务逻辑
    @Override
    public Object run() throws ZuulException {
        log.info("通过过滤");
        return null;
    }

    // 真正的过滤规则就是定义在这里的
    // 返回true,则通过过滤
    @Override
    public boolean shouldFilter() {
        // 获取请求上下文
        RequestContext context = RequestContext.getCurrentContext();
        // 从请求上下文中获取请求
        HttpServletRequest request = context.getRequest();

        // 从请求中获取请求参数与uri
        String token = request.getHeader("token");
        String uri = request.getRequestURI();

        // 若/con的访问中没有携带token头信息,则无法通过过滤
        if(uri.contains("/con") && StringUtils.isEmpty(token)) {
            log.warn("未授权");
            // 设置没有通过过滤
            context.setSendZuulResponse(false);
            // 返回的状态码
            context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
            // 返回false,不会调用run()方法了
            return false;
        }
        return true;
    }
}

配置网关限流

通过对请求限流的方式避免系统遭受“雪崩之灾”。

令牌桶限流

流量限制参考 https://www.jianshu.com/p/0cbf1a22a6d1

@Component
@Slf4j
public class BucketRouteFilter extends ZuulFilter {

    //根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)
    //测试用,每秒产生2个令牌,每秒超过两个请求就限流
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

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

    @Override
    public Object run() throws ZuulException {
        log.info("通过过滤");
        return null;
    }

    /**
     * 过滤、限流的实现
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext context = RequestContext.getCurrentContext();
        //tryAcquire尝试获取1个permit,默认超时时间是0,意思是拿不到就立即返回false,
        //可设置请求超时时间 RATE_LIMITER.tryAcquire(1, TimeUnit.SECONDS)
        if(!RATE_LIMITER.tryAcquire()) {
            log.warn("访问量超载");
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(429);
            context.setResponseBody("服务器繁忙");
            return false;
        }
        return true;
    }
}
zuul推荐限流方式(spring-cloud-zuul-ratelimit)

源码地址 https://github.com/qiuweili123/spring-cloud-zuul-ratelimit

        <!-- spring-cloud-zuul-ratelimit依赖 -->
        <dependency>
            <groupId>com.marcosbarbero.cloud</groupId>
            <artifactId>spring-cloud-zuul-ratelimit</artifactId>
            <version>2.0.5.RELEASE</version>
        </dependency>

限流策略(限流查验的对象)类型有:

  • user:针对用户的限流,即对单位时间窗内经过网关的用户数量进行限制
  • origin:针对客户端 IP 的限流,即对单位时间窗内经过网关的 IP 数量进行限制
  • url:针对请求 URL 的限流,即对单位时间窗内经过网关的请求数量进行限制
zuul:
    routes:
        consumer-service: /aaa/**

  # 对限流策略进行配置
    ratelimit:
        # 开启zuul限流
        enabled: true
        repository: redis
        #默认 - 针对所有的路由配置的策略,除非特别配置了policy-list:
        default-policy-list:
          #可选 - 每个刷新时间窗口对应的请求数量限制
          limit: 10
          #可选-  每个刷新时间窗口对应的请求时间限制(秒)
          # quota: 1000
          # 刷新时间窗口的时间,默认值 (秒)
          refresh-interval: 60
          #可选 限流方式
          type:
            - user
            - origin
            - url
        #指定特定服务的限流策略,覆盖默认
        policy-list:
          myServiceId:
            limit: 10
            quota: 1000
            refresh-interval: 60
            type:
              - user

限流触发的提示页面
在 src/main/resources 目录下再定义新的目录 public/error,必须是这个目录名称。
type:
- user
- origin
- url
#指定特定服务的限流策略,覆盖默认
policy-list:
myServiceId:
limit: 10
quota: 1000
refresh-interval: 60
type:
- user

限流触发的提示页面  
在 src/main/resources 目录下再定义新的目录 public/error,必须是这个目录名称。  
在该目录中定义一个异常处理页面,名称必须是异常状态码,扩展名必须为 html。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

占星安啦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值