今天就跟大家聊聊有关Springcloud中zuul的过滤头部是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
Springcloud的版本是Greenwich.SR2,Springboot版本是2.1.6.release.
在使用zuul时,我有俩个需求,一是不让zuul过滤头部的Cookie,二是要在zuul网关对request的header设置requestId——便于链路追踪。
在网上搜了下,发现sensitiveHeaders和ignoredHeaders描述的较多,但是大多描述的不是较详细,同时自己也想知道底层上是如何做的,所以看了下源码,记录下。如下List-1,在application.yml中设置zuul的sensitiveHeaders和ignoredHeaders,先来说结论,sensitiveHeaders的值设置为x1后servletRequest header的x1不会传到下游;ignoredHeaders的值设置为x2后,servletRequest header的x2不会传到下游。
List-1
zuul: sensitiveHeaders: x1 ignoredHeaders: x2
如下List-2所示,List-1中的配置会被Spring解析到ZuulProperties,sensitiveHeaders是有默认值的,即Cookie、Set-Cookie、Authorization。
List-2
@ConfigurationProperties("zuul") public class ZuulProperties { ... private Set<String> ignoredHeaders = new LinkedHashSet<>(); ... private Set<String> sensitiveHeaders = new LinkedHashSet<>( Arrays.asList("Cookie", "Set-Cookie", "Authorization")); ...
来看PreDecorationFilter的run方法实现,如下List-3,1处和2处,会将ZuulProperties中sensitiveHeaders的值加入到要过滤的字段里面,来看下ProxyRequestHelper的addIgnoredHeaders方法,如下List-4所示,RequestContext是个ConcurrentHashMap,
List-3
public class PreDecorationFilter extends ZuulFilter { ... @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); final String requestURI = this.urlPathHelper .getPathWithinApplication(ctx.getRequest()); Route route = this.routeLocator.getMatchingRoute(requestURI); if (route != null) { String location = route.getLocation(); if (location != null) { ctx.put(REQUEST_URI_KEY, route.getPath()); ctx.put(PROXY_KEY, route.getId()); if (!route.isCustomSensitiveHeaders()) { this.proxyRequestHelper.addIgnoredHeaders(//1 this.properties.getSensitiveHeaders().toArray(new String[0])); } else { this.proxyRequestHelper.addIgnoredHeaders(//2 route.getSensitiveHeaders().toArray(new String[0])); } ... }
List-4
public void addIgnoredHeaders(String... names) { RequestContext ctx = RequestContext.getCurrentContext(); if (!ctx.containsKey(IGNORED_HEADERS)) { ctx.set(IGNORED_HEADERS, new HashSet<String>()); } @SuppressWarnings("unchecked") Set<String> set = (Set<String>) ctx.get(IGNORED_HEADERS); for (String name : this.ignoredHeaders) { set.add(name.toLowerCase());//1 } for (String name : names) { set.add(name.toLowerCase());//2 } }
List-4中,1处this.ignoredHeaders()会获取ZuulProperties中的ignoredHeaders,之后加入到HashSet中。
2处,将方法上的参数值全部加入到HashSet中。
这样,我们设置的sensitiveHeaders和ignoredHeaders全部加到HashSet中,需要注意的是1处和2处都调用了toLowerCase()方法,所以下游收到的header中的字段key都是小写的。
来看RibbonRoutingFilter的run方法,如下List-5,run()调用buildCommandContext来构造RibbonCommand,buildCommandContext方法中调用了ProxyRequestHelper的buildZuulRequestHeaders方法,如List-6所示。
List-5
@Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); this.helper.addIgnoredHeaders(); try { RibbonCommandContext commandContext = buildCommandContext(context); ClientHttpResponse response = forward(commandContext); setResponse(response); return response; ... } protected RibbonCommandContext buildCommandContext(RequestContext context) { HttpServletRequest request = context.getRequest(); MultiValueMap<String, String> headers = this.helper .buildZuulRequestHeaders(request); ... }
List-6
public MultiValueMap<String, String> buildZuulRequestHeaders( HttpServletRequest request) { RequestContext context = RequestContext.getCurrentContext(); MultiValueMap<String, String> headers = new HttpHeaders(); Enumeration<String> headerNames = request.getHeaderNames(); if (headerNames != null) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); if (isIncludedHeader(name)) {//1 Enumeration<String> values = request.getHeaders(name); while (values.hasMoreElements()) { String value = values.nextElement(); headers.add(name, value); } } } } Map<String, String> zuulRequestHeaders = context.getZuulRequestHeaders(); for (String header : zuulRequestHeaders.keySet()) { if (isIncludedHeader(header)) {//2 headers.set(header, zuulRequestHeaders.get(header)); } } if (!headers.containsKey(HttpHeaders.ACCEPT_ENCODING)) { headers.set(HttpHeaders.ACCEPT_ENCODING, "gzip"); } return headers; } public boolean isIncludedHeader(String headerName) { String name = headerName.toLowerCase(); RequestContext ctx = RequestContext.getCurrentContext(); if (ctx.containsKey(IGNORED_HEADERS)) { Object object = ctx.get(IGNORED_HEADERS); if (object instanceof Collection && ((Collection<?>) object).contains(name)) { return false; } } switch (name) { case "host": if (addHostHeader) { return true; } case "connection": case "content-length": case "server": case "transfer-encoding": case "x-application-context": return false; default: return true; } }
获取HttpServletRequest的header,之后遍历,调用isIncludedHeader方法,isIncludedHeader里面获取RequestContext,判断当前的这个header key是不是在IGNORED_HEADERS这个集合里面——List-4中设置的,如果在里面,那么返回false,不会将这个header字段往下游传。
2处,context.getZuulRequestHeaders()获取我们手动设置的header(调用addZuulResponseHeader方法设置),之后逐个遍历,如果在IGNORED_HEADERS这个集合里面——List-4中,则不会加入到headers中,即不往下游传。
注:链路为什么从PreDecorationFilter到RibbonRoutingFilter的,这和Zuul的内部的ZuulFilter机制有关。
要注意的是,如果要往下游传的header含有大写的,那么下游接收到的header是小写的,原因在List-4中可以看出。
看完上述内容,你们对Springcloud中zuul的过滤头部是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。