zuul开发实战(限流,超时解决)

什么是网关
  API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能
  统一接入
    * 智能路由
    * AB测试、灰度测试
    * 负载均衡、容灾处理
    * 日志埋点(类似Nignx日志)
  流量监控
    * 限流处理
    * 服务降级
  安全防护
    * 鉴权处理
    * 监控
    * 机器网络隔离
主流的网关
  zuul:是Netflix开源的微服务网关,和Eureka,Ribbon,Hystrix等组件配合使用,Zuul 2.0比1.0的性能提高很多
  kong: 由Mashape公司开源的,基于Nginx的API gateway
  nginx+lua:是一个高性能的HTTP和反向代理服务器,lua是脚本语言,让Nginx执行Lua脚本,并且高并发、非阻塞的处理各种请求

1. zuul路由案例:
  1. 导入依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- eureka client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- zuul网关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
View Code

  2. 注册到eureka

server:
  port: 9000

#服务的名称
spring:
  application:
    name: api_gatway

#指定注册中心地址ַ
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

  3. 主函数开启zuul注解,并且启动

@SpringBootApplication
@EnableZuulProxy// 开启网关代理
public class ApiGatwayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatwayApplication.class, args);
    }
}

测试:可以看到服务都已经注册到eureka上了,我们不用配置任何路由规则就可以直接通过注册的服务名称来路由

2. 自定义路由规则:

#自定义路由映射(配置文件加入这段配置就好了)
zuul:
  routes:
    order-service: /apigateway/order/**  #配置后就不能通过serverName访问了。
    product-service: /apigateway/product/**
  #忽略满足条件的服务(即:忽略所有-service结尾的服务)
  ignored-patterns: /*-service/**
  #解决http请求头为空的问题 (值为空就好了)
  sensitive-headers:

 

 3. 自定义过滤器url校验 / 限流:

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import org.springframework.http.HttpStatus;
/**
 * 拦截指定url, 进行参数校验
 */
@Component
public class UrlFilter extends ZuulFilter {

//    private String pre_filterType = PRE_TYPE;    // 前置过滤器(url之前执行)
//    private String post_filterType = POST_TYPE;  // 后置过滤器
//    private String error_filterType = ERROR_TYPE;// 异常过滤器
    /**
     * 过滤器类型
     * @return
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }
    /**
     * 过滤器顺序(多个过滤器时, 越小的越先执行)
     * @return
     */
    @Override
    public int filterOrder() {

        return 3;
    }


    /**
     * 过滤器是否生效
     *  为false时就不会走run()里面的业务逻辑
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest  request = requestContext.getRequest();

        // System.out.println(request.getRequestURI());
        // System.out.println(request.getRequestURL());

        if ("/apigateway/order/api/v1/order/find".equalsIgnoreCase(request.getRequestURI())){
            return true;
        }
        return false;
    }

    /**
     * 业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        System.out.println("拦截逻辑");
        RequestContext requestContext =  RequestContext.getCurrentContext();
        HttpServletRequest  request = requestContext.getRequest();

        //token对象
        String id = request.getHeader("id");

        if(StringUtils.isBlank((id))){
            id  = request.getParameter("id");
        }

        //如果id参数为null就程序停止,  同时返回  HttpStatus.UNAUTHORIZED  状态码
        if (StringUtils.isBlank(id)) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import org.springframework.http.HttpStatus;
import com.google.common.util.concurrent.RateLimiter;
/**
 * 网关限流
 */
@Component
public class RequestFilter extends ZuulFilter {


    //每秒产生1000个令牌
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);

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

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

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

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        System.out.println("获取令牌");
        boolean tryAcquire = RATE_LIMITER.tryAcquire();
        // 如果获取不到就直接停止
        if(!tryAcquire){
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        }
        return null;
    }
}

解决zuul超时问题,  完整配置文件  (设置ribbon  hystrix  zuul 超时时间,最好超时时间值比被代理的服务要大。ps: 不需要添加其他依赖包,就一个zuul依赖就好了)

server:
  port: 9000

spring:
  application:
    name: api_gatway

# eureka注册地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/


ribbon:
  ReadTimeout: 7000 #超时时间
  ConnectTimeout: 2000 #连接时间
  MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用
  MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用
  OkToRetryOnAllOperations: false  #是否所有操作都重试
  
#解决hystrix+feign超时设置
feign:
  hystrix: #开启feign支持hystrix (注意:一定要开启,旧版本默认支持,新版本默认关闭)
    enabled: true

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 7000


# ========================================================
#  不配置路由规则,默认可以用服务注册名称来路由
#  商品服务:http://localhost:9000/product-service/api/v1/product/list
#  订单服务:http://localhost:9000/order-service/api/v1/order/find?id=3

#  自定义路由规则
zuul:
  routes:
    order-service: /apigateway/order/**
    product-service: /apigateway/product/**
  # 禁止对product-service服务路由  (支持多个,逗号隔开就好了)
  #ignored-services: product-service
  # 禁止对所有-service结尾的服务路由
  ignored-patterns: /*-service/**
  # 解决http请求头为空的问题 (值为空就好了)
  sensitive-headers:
  #ignored-headers: accept-language  路由时,不向第三方传递请求头
  #sensitive-headers: cookie         路由时,不向第三方传递cookie
  host:
    socket-timeout-millis: 7000
    connect-timeout-millis: 7000

 # 经过上面的自定义路由之后
 # 访问product-service   http://localhost:9000/apigateway/product/api/v1/product/list
 # 访问order-service     http://localhost:9000/apigateway/order/api/v1/order/find?id=3
原文地址:https://www.cnblogs.com/wlwl/p/10413151.html