Zuul 中自帶了一個 DebugFilter,一開始筆者也沒明白這個 DebugFilter 有什麼用,看名稱很容易理解,它是用來調試的,可是你看它的源碼幾乎沒什麼邏輯,就 set 了兩個值而已,代碼如下所示。
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setDebugRouting(true);
ctx.setDebugRequest(true);
return null;
}
要想讓這個過濾器執行就得研究一下它的 shouldFilter() 方法,代碼如下所示。
@Override
public boolean shouldFilter() {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
if ("true".equals(request.getParameter(DEBUG_PARAMETER.get()))) {
return true;
}
return ROUTING_DEBUG.get();
}
只要滿足兩個條件中的任何一個就可以開啓這個過濾器。
第一個條件是請求參數中帶了“某個參數 =true”就可以開啓,這個參數名是通過下面的代碼獲取的,代碼如下所示。
private static final DynamicStringProperty DEBUG_PARAMETER = DynamicPropertyFactory.getInstance()
.getStringProperty(ZuulConstants.ZUUL_DEBUG_PARAMETER, "debug");
DynamicStringProperty 是 Netflix 的配置管理框架 Archaius 提供的 API,可以從配置中心獲取配置,由於 Netflix 沒有開源 Archaius 的服務端,所以這邊用的就是默認值 debug,如果大家想動態去獲取這個值的話可以用攜程開源的 Apollo 來對接 Archaius,教程後面會給大家講解。
可以在請求地址後面追加“debug=true”來開啓這個過濾器,參數名稱 debug 也可以在配置文件中進行覆蓋,用 zuul.debug.parameter 指定,否則就是從 Archaius 中獲取,沒有對接 Archaius 那就是默認值 debug。
第二個條件的代碼,具體代碼如下所示。
private static final DynamicBooleanProperty ROUTING_DEBUG = DynamicPropertyFactory
.getInstance().getBooleanProperty(ZuulConstants.ZUUL_DEBUG_REQUEST, false);
它是通過配置 zuul.debug.request 來決定的,可以在配置文件中配置“zuul.debug.request=true”開啓 DebugFilter 過濾器。
DebugFilter 過濾器開啓後,並沒什麼效果,在 run 方法中只是設置了 DebugRouting 和 DebugRequest 兩個值爲 true,於是繼續看源碼,發現在很多地方都有這樣一段代碼,比如 com.netflix.zuul.FilterProcessor.runFilters(String) 中,代碼如下所示。
if (RequestContext.getCurrentContext().debugRouting()) {
Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
}
當 debugRouting 爲 true 的時候就會添加一些 Debug 信息到 RequestContext 中。現在明白了 DebugFilter 中爲什麼要設置 DebugRouting 和 DebugRequest 兩個值爲 true。
到了這步後還是有些疑惑,一般我們調試信息的話肯定是用日誌輸出來的,日誌級別就是 Debug,但這個 Debug 信息只是累加起來存儲到 RequestContext 中,沒有對使用者展示。
在 org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter.addResponseHeaders() 這段代碼中我們看到了希望。具體代碼如下所示。
private void addResponseHeaders() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletResponse servletResponse = context.getResponse();
if (this.zuulProperties.isIncludeDebugHeader()) {
@SuppressWarnings("unchecked")
List<String> rd = (List<String>) context.get(ROUTING_DEBUG_KEY);
if (rd != null) {
StringBuilder debugHeader = new StringBuilder();
for (String it : rd) {
debugHeader.append("[[[" + it + "]]]");
}
servletResponse.addHeader(X_ZUUL_DEBUG_HEADER, debugHeader.toString());
}
}
}
核心代碼在於 this.zuulProperties.isIncludeDebugHeader(),只有滿足這個條件纔會把 RequestContext 中的調試信息作爲響應頭輸出,在配置文件中增加下面的配置即可:
zuul.include-debug-header=true
最後在請求的響應頭中可以看到調試內容,如圖 1 所示。