Spring Cloud Zuul 网关、拦截器、限流

一. 前言

Zuulspring cloud 中的微服务网关API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能

二. Zuul网关

1. 引入依赖

在pom文件中引入依赖,可以通过idea快速创建 start.spring.io快速创建网关项目

<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. application.yml 配置
server:
  port: 9000
spring:
  application:
    name: api-gateway
#指定注册中心地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
# zuul 网关
zuul:
  routes:
    myuserserver:  #这里是路由id,随意写
      path: /userserver/**  #这里是映射路径
      serviceId: user-server  #配置转发的微服务名称
     
# 另一种路径映射配置方式 
# order-service:服务id /os/**:映射路径
#zuul:
#  routes:
#    order-service: /os/**
3. 添加注解

加上@EnableZuulProxy注解,开启Zuul的功能。代码如下:

@EnableCircuitBreaker 注解默认集成了断路器@EnableCircuitBreaker

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}
4. 自定义路由转发

order-service 为服务id(对应服务在注册中心的名称),以/os/**开头的访问路径都会被分发到order-service服务中

zuul:
  routes:
    order-service: /os/**
5. 环境隔离配置

zull 网关及时不自定义路由转发规则 也有默认访问规则http://gateway:port/service-id/xx,如果不想让默认的服务访问路径对外暴露,我们可以进行如下配置 ignored-patterns 忽略访问路径

zuul:
  ignored-patterns:
    - /*-service/api/v1/**

ignored-patterns 配置为正则表达式

三. 自定义拦截器(登录鉴权)

新建 filter 包,新建一个类实现ZuulFilter并重写方法,在类顶部加注解 @Compoent以下是简单的 登录鉴权演示,拦截器共四种类型(prepostrouteerror),我们这里选择 pre 前置过滤器

@Component
public class LoginFilter extends ZuulFilter{
    
    

	/* 过滤器类型,可选值有 pre、route、post、error */
    @Override
    public String filterType() {
    
    
        return PRE_TYPE;
    }

	/* 过滤器的执行顺序,数值越小,优先级越高 */
    @Override
    public int filterOrder() {
    
    
    	// 过滤器执行顺序,值越小 越先执行
        return 4;
    }

	/* 是否执行该过滤器,true 为执行,false 为不执行,这个也可以利用配置中心来实现,达到动态的开启和关闭过滤器 */
    @Override
    public boolean shouldFilter() {
    
    
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        // 对指定路径进行过滤,返回true后 会进入到 run 方法执行业务逻辑
        if ("/od/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
    
    
            return true;
        }
        return false;
    }

	/* 业务逻辑,本次是判断请求的url是否带有token,没有则通过设置 ctx.setSendZuulResponse(false),
    告诉 Zuul 不需要将当前请求转发到后端的服务了,不需要继续往下走了,通过setResponseBody 返回数据给客户端 */
    @Override
    public Object run() throws ZuulException {
    
    
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)){
    
    
            token = request.getParameter("token");
        }
        if (StringUtils.isBlank(token)){
    
    
        	//是否继续往下走
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

四. 网关限流配置(令牌桶)

filter包中新建RateLimiterFilter类并继承ZuulFilter接口

@Component
public class RateLimiterFilter extends ZuulFilter {
    
    

    /* 定义一个令牌桶,每秒产生1000个令牌,即每秒最多处理1000个请求 */
    private static final RateLimiter  RATE_LIMITER = RateLimiter.create(1000);

    /* 过滤器类型,可选值有 pre、route、post、error */
    @Override
    public String filterType() {
    
    
        return PRE_TYPE;
    }

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

    @Override
    public boolean shouldFilter() {
    
    
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        if ("/od/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())){
    
    
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
    
    
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        /**
         * tryAcquire() 只要能够马上获致到1个令牌,则返回true,不阻塞
         * tryAcquire(5, 3, TimeUnit.SECONDS) 在3秒钟内可以获取到5个令牌,则返回true,不阻塞
         * acquire(5) 获取到5个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
         * acquire() 获取到1个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
         */
        if (!RATE_LIMITER.tryAcquire()) {
    
    
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        }
        return null;
    }
}

五. 常见问题

猜你喜欢

转载自blog.csdn.net/Damao1183297959/article/details/108904508
今日推荐