您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。