Skip to content

zuul网关的使用

依赖

<!--网关的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

配置信息

#服务的名称
spring:
  application:
    name: zuul-gateway
zuul:
  routes:
    #服务名 : 修改后的服务别名  服务之间的名称不能重复否则会覆盖
    order-service: /order/**
    product-service: /product/**
  #忽略整个服务,不对外提供接口。但是可以通过路由的配置访问,可以通过/*-service/**过滤所有的服务,只能通过路由配置的别名访问
# ignored-services: order-service
  ignored-services: /*-service/**
  #网关默认会把header的cookie、Set-Cookie、Authorization这三个参数过滤
  sensitive-headers:

启动类增加注解

在启动类当中增加注解@EnableZuulProxy(包含了@EnableCircuitBreaker,默认集成断路器),开启zuul网关的代理。

通过网关访问服务

通过网关的服务必须都是在一个注册中心下。如果没有在配置文件对服务名进行一个别名修改,则调用规则如下:

http://ip:网关port/服务名/url

,如:localhost:9000/order-service/saveProductOrder

通过配置文件修改了服务别名,将order-service修改成order,调用地址如下:

localhost:9000/order/saveProductOrder

http请求过滤

zuul的配置类是在ZuulProperties当中。http的请求的头部参数中,网关默认会把header的敏感信息cookie、Set-Cookie、Authorization这三个参数过滤, 如果网络权限是根据cookie获取权限的,需要在配置文件开放。

zuul:
 #网关默认会把header的cookie、Set-Cookie、Authorization这三个参数过滤
 sensitive-headers:

自定义过滤器

新建一个继承ZuulFilter的类,并且实现。在类的顶部增加@component让spring能够扫描。

zuul过滤主要有几种,前置过滤器(请求过滤)、路由过滤器(转发到源服务地址)、后置过滤器(结果过滤)和error过滤器(错误信息过滤)。

具体实现如下:

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * @Description TODO
 * @Author lcy
 * @Date 2020/5/1 14:01
 */
@Component
public class LoginFilter extends ZuulFilter {

    /**
     * FilterConstants包含以下四种过来类型
     * ERROR_TYPE = "error"; 错误过滤器
     * POST_TYPE = "post";  后置过滤器
     * PRE_TYPE = "pre";  前置过滤器
     * ROUTE_TYPE = "route";  路由过滤器
     * @return java.lang.String
     **/
    @Override public String filterType(){
        return PRE_TYPE;
    }

    /**
     * 过滤器执行顺序,过滤器的order值越小,越先执行。但是不能早于servlet过滤器等,在FilterConstants中搜索ORDER
     * 或者找到PRE_DECORATION_FILTER_ORDER(执行前置的顺序)。根据需求进行选择
     * @return int
     **/
    @Override public int filterOrder(){
        return 4;
    }

    /**
     * 过滤器是否生效 可以根据业务需求进行过滤
     * @return boolean
     **/
    @Override public boolean shouldFilter(){

        //获取请求上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取请求的对象
        HttpServletRequest request = currentContext.getRequest();
        //根据url决定是否生效
        return "/order/saveProductOrder".equalsIgnoreCase(request.getRequestURI());
    }

    /**
     * 拦截内容
     * @return java.lang.Object
     **/
    @Override public Object run() throws ZuulException{

        //获取请求上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取请求的对象
        HttpServletRequest request = currentContext.getRequest();
        //获取token
        String headerToken = request.getHeader("token");
        String paramToken = request.getParameter("token");

        //判断token是否为空
        if (StringUtils.isBlank(headerToken) && StringUtils.isBlank(paramToken)) {
            //直接返回
            currentContext.setSendZuulResponse(false);
            //返回的状态码  从HttpStatus类获取
            currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
        }

        return null;
    }
}

通过谷歌guava框架进行限流

import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * @Description 限流
 * @Author lcy
 * @Date 2020/5/1 15:01
 */
@Component
public class RateLimiterFilter extends ZuulFilter {

    /** 限流的类 每秒产生1000个令牌,即限流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(){
        //获取请求上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取请求的对象
        HttpServletRequest request = currentContext.getRequest();
        //根据url决定是否生效
        return "/order/saveProductOrder".equalsIgnoreCase(request.getRequestURI());
    }

    @Override public Object run() throws ZuulException{
        //获取请求上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        if(!RATE_LIMITER.tryAcquire()){
            //直接返回
            currentContext.setSendZuulResponse(false);
            //返回的状态码  从HttpStatus类获取
            currentContext.setResponseStatusCode(HttpStatus.SC_REQUEST_TIMEOUT);
        }

        return null;
    }
}

网关集群

在用户访问网关之前,最好使用nginx+lvs+keepalive的反向代理,对网关的集群进行代理和转发

zuul集群只需要多启动几个应用同时注册在注册中心。