1、zuulFilter 四个方法
继承zuulFilter需要实现四个方法,filterType、filterOrder、shouldFilter、run
- filterType():过滤器执行类型。有以下四种类型pre、route、post、error
- filterOrder():过滤器执行顺序,数字越大,优先级越低
- shouldFilter():是否执行该过滤器,此处为true,则会执行run方法
- run():过滤器具体执行逻辑
2、过滤器类型 filterType
-
pre:请求被路由到源服务器之前执行的过滤器
身份认证
选路由
请求日志 -
route:处理将请求发送到源服务器的过滤器
-
post:响应从源服务器返回时执行的过滤器
对响应增加 HTTP 头
收集统计和度量指标
将响应以流的方式发送回客户端 -
error:上述阶段中出现错误时执行的过滤器
3、过滤器实例
Spring Cloud Netflix Zuul 中实现过滤器必须包含 4 个基本特征:过滤器类型,执
行顺序,执行条件,动作(具体操作)。这些步骤都是 ZuulFilter 接口中定义的
4 个抽象方法:
package com.xxxx.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* 网关过滤器:校验token
*/
@Component
public class CustomFilter extends ZuulFilter {
private static final Logger logger =
LoggerFactory.getLogger(CustomFilter.class);
/**
* 过滤器类型
* pre
* routing
* post
* error
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 执行顺序
* 数值越小,优先级越高
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 执行条件
* true 开启
* false 关闭
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 动作(具体操作)
* 具体逻辑
*
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext rc = RequestContext.getCurrentContext();
HttpServletRequest request = rc.getRequest();
// 获取表单中的 token
String token = request.getParameter("token");
// 业务逻辑处理
if (null == token) {
logger.warn("token is null...");
// 请求结束,不在继续向下请求。
rc.setSendZuulResponse(false);
// 响应状态码,HTTP 401 错误代表用户没有访问权限
rc.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
// 响应类型
rc.getResponse().setContentType("application/json;
charset=utf-8");
PrintWriter writer = null;
try {
writer = rc.getResponse().getWriter();
// 响应内容
writer.print("{\"message\":\"" +
HttpStatus.UNAUTHORIZED.getReasonPhrase() + "\"}");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != writer)
writer.close();
}
} else {
// 使用 token 进行身份验证
logger.info("token is OK!");
}
return null;
}
}
4、Zuul生命周期
5、网关过滤器异常统一处理
- 禁用 Zuul 默认异常
zuul:
# 禁用 Zuul 默认的异常处理 filter
SendErrorFilter:
error:
disable: true
- 实现自定义异常
package com.xxxx.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 异常过滤器
*/
@Component
public class ErrorFilter extends ZuulFilter {
private static final Logger logger =
LoggerFactory.getLogger(ErrorFilter.class);
@Override
public String filterType() {
return "error";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext rc = RequestContext.getCurrentContext();
Throwable throwable = rc.getThrowable();
logger.error("ErrorFilter..." +
throwable.getCause().getMessage(), throwable);
// 响应状态码,HTTP 500 服务器错误
rc.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
// 响应类型
rc.getResponse().setContentType("application/json;
charset=utf-8");
PrintWriter writer = null;
try {
writer = rc.getResponse().getWriter();
// 响应内容
writer.print("{\"message\":\"" +
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase() + "\"}");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != writer)
writer.close();
}
return null;
}
}