zuul-filter有四个生命周期分别是“pre”、“routing”、“error”、“post”,如下图所示
image.pngZuul 大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。
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;
}
}
执行顺序如上图所示
网友评论