作为网关至少要有三大功能:

1.路由功能,能够将内外网分离。

2.过滤功能,包括登录鉴权等

3.限流的功能

为了能够满足网关的上述的三大功能这里选择了Zuul+RateLimiter 来实现。

1.application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8081/eureka/
server:
  port: 8087
spring:
  application:
    name: api_gateway
  redis:
    host: localhost
    port: 6379

zuul:
  routes:
    order_service: /api_gateway/**
    ignored-services: "*_service/**"

2.pom.xml 主要的包:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>27.0-jre</version>
</dependency>

3.路由功能

zuul:
  routes:
    order_service: /api_gateway/**
    ignored-services: "*_service/**"

原来直接请求/order_service订单服务,通过zuul的路由配置统一通过/api_gateway/来请求,隐藏了真实的内网服务路径。当然这里需要结合物理网络进行内外网隔离。

4.登录鉴权

登录鉴权是通过ZuulFilter 来进行过滤的。

@Component
 public class LoginFilter  extends ZuulFilter {

    /**
       * 过滤器类型,前置过滤器
      * @return
      */
    @Override
     public String filterType() {
        return "pre";
    }

    /**
       * 过滤器顺序,越小越先执行
       * @return
      */
    @Override
    public int filterOrder() {
        return 1;
    }

    /**
     * 过滤器是否生效
      * @return
      */
    @Override
    public boolean shouldFilter() {
        System.out.println("ZuulExceptionZuulException");
       RequestContext requestContext = RequestContext.getCurrentContext();
       HttpServletRequest request = requestContext.getRequest();
       System.out.println("request.getRequestURI():"+request.getRequestURI());
      //ACL
       if ("/api_gateway/order/getOrderDetailById.do".equalsIgnoreCase(request.getRequestURI())){
             return true;
       }
        return false;
    }

        /**
         * 业务逻辑
        * @return
        * @throws ZuulException
        */
        @Override
        public Object run() throws ZuulException {
            System.out.println("ZuulExceptionZuulException");
            //JWT
            RequestContext requestContext =  RequestContext.getCurrentContext();
           HttpServletRequest request = requestContext.getRequest();
           //token对象
            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;
       }
    }

5. 网关限流

限流是通过Guava限流工具RateLimiter来实现的。

@Component
public class RateLimitFilter  extends ZuulFilter {
     private  static  final  RateLimiter rateLimiter= RateLimiter.create(2);
    /**
     * 过滤器类型,前置过滤器
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤器顺序,越小越先执行
     * @return
     */
    @Override
    public int filterOrder() {
        return -1;
    }

    /**
     * 过滤器是否生效
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        if ("/api_gateway/order/getOrderDetailById.do".equalsIgnoreCase(request.getRequestURI())){
            System.out.println("request.getRequestURI():"+request.getRequestURI());
            return true;
        }
        return false;
    }

    /**
     * 业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext =  RequestContext.getCurrentContext();
        HttpServletResponse response= requestContext.getResponse();
        if (!rateLimiter.tryAcquire()) {

            try {
                requestContext.setSendZuulResponse(false);
                String data = "请求频繁,暂时限流";
                OutputStream outputStream = response.getOutputStream();
                response.setHeader("content-type", "text/html;charset=UTF-8");
                byte[] dataByteArr = data.getBytes("UTF-8");
                outputStream.write(dataByteArr);
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
        return null;
    }
}

其中 private static final RateLimiter rateLimiter= RateLimiter.create(2); 是每秒产生两个令牌。rateLimiter.tryAcquire() 无法获取令牌则请求太过于频繁给出提示。

效果如下图:

 

 

 

 

 

 

 

 

 
 

 

 

 


版权声明:本文为qq_40263927原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_40263927/article/details/110734162