@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); try { filterChain.doFilter(requestWrapper, responseWrapper); } finally { String requestBody = new String(requestWrapper.getContentAsByteArray()); log.info("Request body: {}", requestBody); String responseBody = new String(responseWrapper.getContentAsByteArray()); log.info("Response body: {}", responseBody); // Do not forget this line after reading response content or actual response will be empty! responseWrapper.copyBodyToResponse(); } }
/** * 提取请求结果 * @param request * @param loggingContext * @return */ protected Object extractResponseResult(HttpServletResponse response, LoggingContext loggingContext) throws Exception { MediaType contentType = loggingContext.getHttpAccessLog().getResponseContentType(); if(contentType != null){ if(isContentCachingResponse(response)){ String charset = response.getCharacterEncoding(); if(StringUtils.isEmpty(charset)){ charset = StringUtils.defaultIfEmpty(contentType.getCharset().name(), GlobalConstants.SYSTEM_DEFAULT_CHARSET); } ContentCachingResponseWrapper responseToUse = (ContentCachingResponseWrapper) response; byte[] bytes = responseToUse.getContentAsByteArray(); if(bytes != null){ return IOUtils.toString(bytes, charset); } } } return null; }
private void updateResponse(String requestURI, ContentCachingResponseWrapper responseWrapper) throws IOException { try { HttpServletResponse rawResponse = (HttpServletResponse) responseWrapper.getResponse(); byte[] body = responseWrapper.getContentAsByteArray(); ServletOutputStream outputStream = rawResponse.getOutputStream(); if (rawResponse.isCommitted()) { if (body.length > 0) { StreamUtils.copy(body, outputStream); } } else { if (body.length > 0) { rawResponse.setContentLength(body.length); StreamUtils.copy(body, rawResponse.getOutputStream()); } } finishResponse(outputStream, body); } catch (Exception ex) { logger.error("请求地址为" + requestURI + "的连接返回报文失败,原因是{}", ex.getMessage()); } }
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { long begintime = DateUtils.currentTimeMillis(); JsonContentCachingRequestWrapper requestWrapper = new JsonContentCachingRequestWrapper(request); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); filterChain.doFilter(requestWrapper, responseWrapper); long timecost = DateUtils.getTimeMillisConsume(begintime); String requestURI = request.getRequestURI(); String ip = request.getRemoteAddr(); String requestParam = convertString(requestWrapper.getContentAsByteArray()); updateResponse(requestURI, responseWrapper); if (isNotJsonContentType(responseWrapper.getContentType())) { logger.debug("ip:{} 调用接口,请求地址为:{}, 请求参数为:{},[{}]ms", ip, requestURI, requestParam, timecost); } else { String result = convertString(responseWrapper.getContentAsByteArray()); logger.debug("ip:{} 调用接口,请求地址为:{}, 请求参数为:{},返回值是{},[{}]ms", ip, requestURI, requestParam, result, timecost); } }
private static String getResponseContent(HttpServletResponse response) { if (response instanceof ContentCachingResponseWrapper) { return new String(((ContentCachingResponseWrapper) response).getContentAsByteArray()); } if (response instanceof HttpServletResponseWrapper && ((HttpServletResponseWrapper) response).getResponse() instanceof ContentCachingResponseWrapper) { return new String(((ContentCachingResponseWrapper) ((HttpServletResponseWrapper) response) .getResponse()).getContentAsByteArray()); } log.warn("Empty response content because of unsupported response class {}", response.getClass()); return ""; }
/** * wrap the {@link HttpServletResponse} in a {@link ContentCachingResponseWrapper} if it is not already one. * * @param httpServletResponse * @return */ protected ContentCachingResponseWrapper wrapResponseIfNeeded(HttpServletResponse httpServletResponse) { if (!(httpServletResponse instanceof ContentCachingResponseWrapper)) { return new ContentCachingResponseWrapper(httpServletResponse); } else { return (ContentCachingResponseWrapper) httpServletResponse; } }
protected boolean isContentCachingResponse(ServletResponse response) { if(response instanceof ContentCachingResponseWrapper){ return true; }else if(response instanceof HttpServletResponseWrapper) { HttpServletResponseWrapper responseToUse = (HttpServletResponseWrapper) response; return isContentCachingResponse(responseToUse.getResponse()); } return false; }
/** * 获取ContentCachingResponseWrapper * (考虑到Wrapper是可以重复的,故需要递归获取) * @param response * @return */ protected ContentCachingResponseWrapper getContentCachingResponseWrapper(ServletResponse response) { if(response instanceof ContentCachingResponseWrapper){ return (ContentCachingResponseWrapper) response; }else if(response instanceof HttpServletResponseWrapper) { HttpServletResponseWrapper responseToUse = (HttpServletResponseWrapper) response; return getContentCachingResponseWrapper(responseToUse.getResponse()); } return null; }
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); try { filterChain.doFilter(requestWrapper, responseWrapper); } finally { responseWrapper.copyBodyToResponse(); } }
@Test public void doFilterInternal_NoCacheRequestAndResponse_CallWithCacheRequestAndResponse() throws Exception { HttpServletRequest request = new MockHttpServletRequest(); HttpServletResponse response = new MockHttpServletResponse(); FilterChain filterChain = spy(new MockFilterChain()); FILTER.doFilterInternal(request, response, filterChain); Mockito.verify(filterChain).doFilter(isA(ContentCachingRequestWrapper.class), isA (ContentCachingResponseWrapper.class)); }
@Test public void doFilterInternal_CacheRequestAndNoCacheResponse_CallWithCacheRequestAndResponse() throws Exception { HttpServletRequest cacheRequest = new ContentCachingRequestWrapper(new MockHttpServletRequest()); HttpServletResponse response = new MockHttpServletResponse(); FilterChain filterChain = spy(new MockFilterChain()); ArgumentCaptor<HttpServletRequest> requestCaptor = ArgumentCaptor.forClass(HttpServletRequest.class); FILTER.doFilterInternal(cacheRequest, response, filterChain); Mockito.verify(filterChain).doFilter(requestCaptor.capture(), isA(ContentCachingResponseWrapper.class)); assertThat(requestCaptor.getValue(), is(cacheRequest)); }
@Test public void doFilterInternal_NoCacheRequestAndCacheResponse_CallWithCacheRequestAndResponse() throws Exception { HttpServletRequest request = new MockHttpServletRequest(); HttpServletResponse cacheResponse = new ContentCachingResponseWrapper(new MockHttpServletResponse()); FilterChain filterChain = spy(new MockFilterChain()); ArgumentCaptor<HttpServletResponse> responseCaptor = ArgumentCaptor.forClass(HttpServletResponse.class); FILTER.doFilterInternal(request, cacheResponse, filterChain); Mockito.verify(filterChain).doFilter(isA(ContentCachingRequestWrapper.class), responseCaptor.capture()); assertThat(responseCaptor.getValue(), is(cacheResponse)); }
@Test public void buildResponseLog_WithNoBody_ReturnStringResponseWithUriAndEmptyBody() { MockHttpServletResponse response = new MockHttpServletResponse(); String log = FILTER.buildResponseLog(new ContentCachingResponseWrapper(response)); assertThat(log, is("Server responded with a response\n > 200\n[empty]")); }
@Test public void buildResponseLog_WithCorrectBody_ReturnStringResponseWithUriAndBody() throws IOException { MockHttpServletResponse response = new MockHttpServletResponse(); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); responseWrapper.getWriter().print("test"); String log = FILTER.buildResponseLog(responseWrapper); assertThat(log, is("Server responded with a response\n > 200\ntest")); }
@Test public void buildResponseLog_WithUnreadableBody_ReturnStringResponseWithUriAndUnknownBody() throws IOException { MockHttpServletResponse response = new MockHttpServletResponse(); ContentCachingResponseWrapper responseWrapper = spy(new ContentCachingResponseWrapper(response)); responseWrapper.getWriter().print("test"); //noinspection InjectedReferences responseWrapper.setCharacterEncoding("notExistThisEncoding"); String log = FILTER.buildResponseLog(responseWrapper); assertThat(log, is("Server responded with a response\n > 200\n[unknown]")); }
void appendResponseCommonMessage(ContentCachingResponseWrapper response, long cost) { normalMsg.append(RESPONSE_PREFIX); StringBuilder msg = new StringBuilder(); msg.append("status=").append(response.getStatusCode()); msg.append(";size=").append(response.getContentSize()); msg.append(";cost=").append(cost); normalMsg.append(msg.toString()); }
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletResponse responseToUse = response; if (!isAsyncDispatch(request) && !(response instanceof ContentCachingResponseWrapper)) { responseToUse = new HttpStreamingAwareContentCachingResponseWrapper(response, request); } filterChain.doFilter(request, responseToUse); if (!isAsyncStarted(request) && !isContentCachingDisabled(request)) { updateResponse(request, responseToUse); } }
private void updateResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class); Assert.notNull(responseWrapper, "ContentCachingResponseWrapper not found"); HttpServletResponse rawResponse = (HttpServletResponse) responseWrapper.getResponse(); int statusCode = responseWrapper.getStatusCode(); if (rawResponse.isCommitted()) { responseWrapper.copyBodyToResponse(); } else if (isEligibleForEtag(request, responseWrapper, statusCode, responseWrapper.getContentInputStream())) { String responseETag = generateETagHeaderValue(responseWrapper.getContentInputStream()); rawResponse.setHeader(HEADER_ETAG, responseETag); String requestETag = request.getHeader(HEADER_IF_NONE_MATCH); if (responseETag.equals(requestETag)) { if (logger.isTraceEnabled()) { logger.trace("ETag [" + responseETag + "] equal to If-None-Match, sending 304"); } rawResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } else { if (logger.isTraceEnabled()) { logger.trace("ETag [" + responseETag + "] not equal to If-None-Match [" + requestETag + "], sending normal response"); } responseWrapper.copyBodyToResponse(); } } else { if (logger.isTraceEnabled()) { logger.trace("Response with status code [" + statusCode + "] not eligible for ETag"); } responseWrapper.copyBodyToResponse(); } }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest)) { return; } ContentCachingRequestWrapper wrapperRequest = new ContentCachingRequestWrapper((HttpServletRequest) request); ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper((HttpServletResponse) response); String ua = wrapperRequest.getHeader("User-Agent"); ua = null == ua ? "" : ua; if (ua.equals("KeepAliveClient") || HttpMethod.HEAD.matches(wrapperRequest.getMethod())) { chain.doFilter(wrapperRequest, wrapperResponse); wrapperResponse.copyBodyToResponse(); } else { ApplicationContext context = ACU.ctx(); logFilterInterceptorList.forEach(LogFilterInterceptor::prepare); StringBuilder accessLogBuilder = new StringBuilder(); long startTime = Instant.now().toEpochMilli(); addLogKV(accessLogBuilder, "start", String.valueOf(startTime)); chain.doFilter(wrapperRequest, wrapperResponse); addLogKV(accessLogBuilder, "status", String.valueOf(wrapperResponse.getStatusCode())); RequestAttributes requestAttributes = (RequestAttributes) context.getBean("requestAttributes"); if (null != requestAttributes.getDeviceToken()) { addLogKV(accessLogBuilder, "vd", (String) requestAttributes.getDeviceToken()); } if (null != requestAttributes.getLoginUser()) { addLogKV(accessLogBuilder, "user", String.valueOf(requestAttributes.getLoginUser().getId())); addLogKV(accessLogBuilder, "token", requestAttributes.getLoginUser().getToken()); addLogKV(accessLogBuilder, "tokenExpireTime", requestAttributes.getLoginUser().getTokenExpireTime().toString ()); } addLogKV(accessLogBuilder, "locale", RequestContextUtils.getLocale(wrapperRequest).toLanguageTag()); String remoteIp = requestAttributes.getRemoteIp(); addLogKV(accessLogBuilder, "prevIp", wrapperRequest.getRemoteAddr()); addLogKV(accessLogBuilder, "remoteIp", remoteIp); addLogKV(accessLogBuilder, "request", wrapperRequest.getRequestURI()); addLogKV(accessLogBuilder, "method", wrapperRequest.getMethod()); addLogKV(accessLogBuilder, "params", parseParams(wrapperRequest.getParameterMap())); addLogKV(accessLogBuilder, "ua", wrapperRequest.getHeader("User-Agent")); if ("POST".equalsIgnoreCase(wrapperRequest.getMethod())) { byte[] content = wrapperRequest.getContentAsByteArray(); if (content.length < 1) { content = StreamUtils.copyToByteArray(wrapperRequest.getInputStream()); } addLogKV(accessLogBuilder, "body", IOUtils.toString(content, "UTF-8").replaceAll("\\r\\n", "") .replaceAll ("\\n", "")); } if (null != wrapperResponse.getContentType() && (wrapperResponse.getContentType().equals(MediaType .APPLICATION_JSON_UTF8_VALUE) || wrapperResponse.getContentType().equals(MediaType .APPLICATION_JSON_VALUE))) { addLogKV(accessLogBuilder, "response", IOUtils.toString(wrapperResponse.getContentAsByteArray(), "UTF-8")); } logFilterInterceptorList.forEach(logFilterInterceptor -> addLogKV(accessLogBuilder, logFilterInterceptor .getKey(), logFilterInterceptor.getOutput())); long endTime = Instant.now().toEpochMilli(); addLogKV(accessLogBuilder, "duration", String.valueOf(endTime - startTime) + "ms"); accessLogger.info(accessLogBuilder.toString()); wrapperResponse.copyBodyToResponse(); } }