一、POST Filter
后置过滤器一般使用来转换响应数据的格式,截取请求响应数据进行流量录制等操作。
Zuul已定义的后置过滤器SendResponseFilter
,将代理请求的响应写入当前响应。
二、自定义后置过滤器
本文自定义后置过滤器用来截取响应体的快照文本发送到kafka存储。
三、实现代码
@Component
@Slf4j
public class PostFilter extends ZuulFilter {//按类型对过滤器进行分类。Zuul中的标准类型是"pre"用于预路由筛选,"route"用于路由到原点,"post"用于后路由筛选,"error"用于错误处理。//我们还支持静态响应的"static"类型请参阅StaticResponseFilter。可以通过调用FilterProcessor.runFilters(type)//后置过滤器必须返回post@Overridepublic String filterType() {return FilterConstants.POST_TYPE;}//必须为过滤器定义filterOrder。如果优先级对筛选器不重要,则过滤器可能具有相同的过滤器顺序//过滤器顺序不需要是连续的@Overridepublic int filterOrder() {return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 10;}//默认情况下,zuulfilter是静态的;它们不携带状态。这可以通过将isStaticFilter属性重写为false来重写@Overridepublic boolean isStaticFilter() {return super.isStaticFilter();}//要禁用此筛选器的Archaius属性的名称。默认情况下,它是zuul.[classname].[filtertype].disable@Overridepublic String disablePropertyName() {return super.disablePropertyName();}//如果为true,则过滤器已被archaius禁用,不会运行@Overridepublic boolean isFilterDisabled() {return super.isFilterDisabled();}//此方法返回的"true"表示应该调用run方法//如果应该调用run方法,则返回true。false不会调用run方法@Overridepublic boolean shouldFilter() {RequestContext context = RequestContext.getCurrentContext();return context.getThrowable() == null&& (!context.getZuulResponseHeaders().isEmpty()|| context.getResponseDataStream() != null|| context.getResponseBody() != null);}//如果shouldFilter方法为true,则将调用此方法。这种方法是ZuulFilter的核心方法//返回一些可以返回的任意工件。当前的实现忽略了它。//如果在执行期间发生错误,则引发ZuulException@Overridepublic Object run() throws ZuulException {RequestContext context = RequestContext.getCurrentContext();InputStream in = null;try {String responseBody = context.getResponseBody();if (responseBody == null) {in = context.getResponseDataStream();ByteArrayOutputStream output = new ByteArrayOutputStream();IOUtils.copy(in, output);byte[] bodyBytes = output.toByteArray();//回填已读的流context.setResponseDataStream(new ByteArrayInputStream(bodyBytes));in = new ByteArrayInputStream(bodyBytes);if (context.getResponseGZipped()) {in = new GZIPInputStream(in);}HttpServletResponse servletResponse = context.getResponse();String endcoding = servletResponse.getCharacterEncoding();if (endcoding == null) {endcoding = "UTF-8";}responseBody = StreamUtils.copyToString(in, Charset.forName(endcoding));}//存储响应数据KafkaUtils.sendResponseDataAsync(context.getRequest().getRequestURI(), responseBody);} catch (Exception e) {log.error("post filter error",e);}finally {if(in!= null){try {in.close();} catch (IOException e) {log.warn("post filter close io error",e);}}}return null;}}