系統在生產環境出現問題時,排查問題最好的方式就是查看日志了,日志的記錄盡量詳細,這樣你才能快速定位問題。
如果需要在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折包郵