Spring Cloud Zuul記錄介面響應資料

尹吉歡發表於2018-08-06

系統在生產環境出現問題時,排查問題最好的方式就是檢視日誌了,日誌的記錄儘量詳細,這樣你才能快速定位問題。

如果需要在Zuul中進行詳細的日誌記錄,這兩種日誌必不可少。

  • API請求資訊
  • API響應資訊

前面有介紹過如何獲取請求資訊,文章請檢視《Spring Cloud Zuul過濾器獲取請求引數問題》

今天正好又有一位朋友問我如何獲取響應的資料,抽時間給大家寫篇文章簡單分享下。

熟悉Zuul的朋友都知道,Zuul中有4種型別過濾器,每種都有特定的使用場景,要想記錄響應資料,那麼必須是在請求路由到了具體的服務之後,返回了才有資料,這種需求就適合用post過濾器來實現了。

這邊給大家介紹兩種方式獲取響應資料:

第一種

try {
     Object zuulResponse = RequestContext.getCurrentContext().get("zuulResponse");
     if (zuulResponse != null) {
         RibbonHttpResponse resp = (RibbonHttpResponse) zuulResponse;
         String body = IOUtils.toString(resp.getBody());
         System.err.println(body);
         resp.close();
         RequestContext.getCurrentContext().setResponseBody(body);
     }
} catch (IOException e) {
	e.printStackTrace();
}

第二種

InputStream stream = RequestContext.getCurrentContext().getResponseDataStream();
try {
	String body = IOUtils.toString(stream);
	System.err.println(body);
	RequestContext.getCurrentContext().setResponseBody(body);
} catch (IOException e) {
	e.printStackTrace();
}

為什麼上面兩種方式可以取到響應內容?

在RibbonRoutingFilter或者SimpleHostRoutingFilter中可以看到下面一段程式碼:

public Object run() {
	RequestContext context = RequestContext.getCurrentContext();
	this.helper.addIgnoredHeaders();
	try {
		RibbonCommandContext commandContext = buildCommandContext(context);
		ClientHttpResponse response = forward(commandContext);
		setResponse(response);
		return response;
	}
	catch (ZuulException ex) {
		throw new ZuulRuntimeException(ex);
	}
	catch (Exception ex) {
		throw new ZuulRuntimeException(ex);
	}
}

forward()方法對服務呼叫,拿到響應結果,通過setResponse()方法進行響應的設定。

protected void setResponse(ClientHttpResponse resp)
		throws ClientException, IOException {
	RequestContext.getCurrentContext().set("zuulResponse", resp);
	this.helper.setResponse(resp.getStatusCode().value(),
	resp.getBody() == null ? null : resp.getBody(), resp.getHeaders());
}

上面第一行程式碼就可以解釋我們的第一種獲取的方法,這邊直接把響應內容加到了RequestContext中。

第二種方式的解釋就在helper.setResponse的邏輯裡面了,如下:

public void setResponse(int status, InputStream entity,
			MultiValueMap<String, String> headers) throws IOException {
	RequestContext context = RequestContext.getCurrentContext();
	context.setResponseStatusCode(status);
	if (entity != null) {
		context.setResponseDataStream(entity);
	}

	// .....
}

第二天又問了另外一個問題,怎麼獲取response的contentType?

需求是可以區分是正常的資料響應還是檔案下載:

這位朋友獲取的程式碼是:

HttpServletResponse response = ctx.getResponse();
response.getContentType()

他說上面的方式獲取不到?

我給大家介紹兩種獲取方式,如下:

第一種

List<Pair<String, String>>  headerList = RequestContext.getCurrentContext().getOriginResponseHeaders();
for (Pair<String, String> pair : headerList) {
	if (pair.first().equals("Content-Type")) {
		System.err.println(pair.second());
	}
}

第二種

Object zuulResponse = RequestContext.getCurrentContext().get("zuulResponse");
if (zuulResponse != null) {
     RibbonHttpResponse resp = (RibbonHttpResponse) zuulResponse;
     System.err.println(resp.getHeaders().getContentType().toString());
}

推薦下我的新書《Spring Cloud微服務-全棧技術與案例解析》

新書購買:單本75折包郵

WechatIMG48.jpeg

歡迎加入我的知識星球,一起交流技術,免費學習猿天地的課程(http://cxytiandi.com/course)

PS:目前星球中正在星主的帶領下組隊學習Spring Cloud,等你哦!

微信掃碼加入猿天地知識星球

猿天地

相關文章