美文网首页
zuul-filter

zuul-filter

作者: jianshuqiang | 来源:发表于2019-05-30 19:46 被阅读0次

zuul-filter有四个生命周期分别是“pre”、“routing”、“error”、“post”,如下图所示

image.png

Zuul 大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient 或 Netfilx Ribbon 请求微服务。

POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等(调用微服务以后执行,也就是处理响应结果)

ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul 还允许我们创建自定义的过滤器类型。例如,我们可以定制一种 STATIC 类型的过滤器,直接在 Zuul 中生成响应,而不将请求转发到后端的微服务。

Zuul 中默认实现的 Filter


image.png

顺序“ORDER”越小执是先执行
下面将自定义三个过滤器,前置、错误、后置

package com.sgcc.zuul.filter;

import com.google.gson.Gson;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.sgcc.zuul.config.TokenProperties;
import com.sgcc.zuul.model.ResultVO;
import com.sgcc.comm.util.CookieUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

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

@Slf4j
@Component
public class AuthFilter extends ZuulFilter {

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    private TokenProperties tokenProperties;
    //无权限时的提示语
    private static final String INVALID_TOKEN = "invalid token";

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

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

    @Override
    public boolean shouldFilter() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        log.info("网关前置过滤器========》》》uri={}", request.getRequestURI());
        if ("false".equals(tokenProperties.getFilterSwitch()) || tokenProperties.getWhiteList().contains(request.getRequestURI())) {
            return false;
        }
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        checkToken(requestContext, request);
        return null;
    }

    /**
     * 校验token
     *
     * @param requestContext
     * @param request
     */
    private void checkToken(RequestContext requestContext, HttpServletRequest request) {
        //先从 cookie 中取 token,cookie 中取失败再从 header 中取,两重校验
        String token = getToken(request);
        //如果获取的token为空,则直接返回401无权限
        if (StringUtils.isEmpty(token)) {
            setUnauthorizedResponse(requestContext, INVALID_TOKEN);
        } else {
            String value = stringRedisTemplate.opsForValue().get(token);
            if (StringUtils.isEmpty(value)) {
                setUnauthorizedResponse(requestContext, INVALID_TOKEN);
            } else {
                String[] values = value.split("_");
                String checkToken = values[0];
                String userId = values[1];
                log.info("当前正在操作的用户ID为userId={}", userId);
            }
        }
    }

    /**
     * 获取token
     *
     * @return
     */
    private String getToken(HttpServletRequest request) {
        String token = CookieUtil.getValue(request, "X-Token");//先从cookie获取
        if (StringUtils.isEmpty(token)) {//如果cookie获取的token为空
            token = request.getHeader("X-Token");//则从header中获取
        }
        return token;
    }
    /**
     * 设置 401 无权限状态
     */
    private void setUnauthorizedResponse(RequestContext requestContext, String msg) {
        log.info("无权限非法请求~");
        requestContext.setSendZuulResponse(false);
        requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        requestContext.getResponse().setCharacterEncoding("UTF-8");
        requestContext.getResponse().setContentType("application/json; charset=utf-8");
        ResultVO resultVO = new ResultVO();
        resultVO.setStatus(401);
        resultVO.setMessage(msg);
        Gson gson = new Gson();
        String result = gson.toJson(resultVO);
        requestContext.setResponseBody(result);
    }
}

package com.sgcc.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.sgcc.zuul.enums.ExceptionTypeEnum;
import com.sgcc.zuul.service.ZuulExceptionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author: 杨文培
 * @Desrcription:错误拦截过滤器
 * @Date: Create in 17:43 2018/12/29
 */
@Component
@Slf4j
public class ErrorFilter extends ZuulFilter {
    @Autowired
    private ZuulExceptionService zuulExceptionService;

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

    @Override
    public int filterOrder() {
        return FilterConstants.SEND_ERROR_FILTER_ORDER - 1;
    }

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

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String url = request.getRequestURI();
        log.info("拦截错误========》》》url={}", url);
        zuulExceptionService.addException(RequestContext.getCurrentContext(), ExceptionTypeEnum.ERROR);
        return null;
    }
}

package com.sgcc.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.sgcc.zuul.enums.ExceptionTypeEnum;
import com.sgcc.zuul.service.ZuulExceptionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: 张强
 * @Desrcription:后置过滤器
 * @Date: Create in 17:43 2018/12/29
 */
@Component
@Slf4j
public class PostFilter extends ZuulFilter {
    @Autowired
    private ZuulExceptionService zuulExceptionService;

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

    @Override
    public int filterOrder() {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
    }

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

    @Override
    public Object run() throws ZuulException {

        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        HttpServletResponse response = requestContext.getResponse();
        String url = request.getRequestURI();
        int status = response.getStatus();
        log.info("网关后置过滤器========》》》url={},status={}", url, status);
        if (200 != status) {
            //网页已经被移到别处
            if (status / 100 != 3) {
                log.info("拦截到一个异常===》url={},status={}", url, status);
                zuulExceptionService.addException(requestContext, ExceptionTypeEnum.EXCEPTION);
            }
        }
        return null;
    }
}

执行顺序如上图所示

相关文章

  • zuul-filter

    zuul-filter有四个生命周期分别是“pre”、“routing”、“error”、“post”,如下图所示...

网友评论

      本文标题:zuul-filter

      本文链接:https://www.haomeiwen.com/subject/tchbtctx.html