如何在HttpComponentsAsyncClientHttpRequestFactory中使用BufferingClientHttpResponseWrapper

时间:2017-02-17 23:32:41

标签: spring spring-boot

以下是从Spring的AsyncRestTemplate进行异步休息调用时记录请求和响应的拦截器代码。 如果我们可以在其他包中使用BufferingClientHttpResponseWrapper,则此代码正常运行。 Here是关于BufferingClientHttpResponseWrapper以及如何使用AsyncRestTemplate添加它的一些详细信息。 我的问题是我在AsyncRestTemplate中使用HttpComponentsAsyncClientHttpRequestFactory时。我如何获得缓冲响应。我们不能在我的代码中使用BufferingClientHttpResponseWrapper如下所示,因为它不是公共类。还有其他办法吗? 我知道HttpComponent AsyncHttpClient有可用的线路日志。但它将包含整个应用程序中所有AsyncResttemplates的所有日志。如果我们只想为一个模板捕获日志,那么拦截器是我认为的唯一方式。如果有其他选择,请建议。

public class AsyncRestReqResInterceptor implements AsyncClientHttpRequestInterceptor {
    private static final XLogger REQ_RES_LOGGER = XLoggerFactory.getXLogger("myLogger");

    @Override
        public ListenableFuture<ClientHttpResponse> intercept(HttpRequest request, byte[] body, AsyncClientHttpRequestExecution execution) throws IOException {
            String requestPath = request.getURI().getPath();
            REQ_RES_LOGGER.debug(request.getMethod()+" "+requestPath);

            String requestBody = new String(body);
            REQ_RES_LOGGER.debug(requestBody);
            ListenableFuture<ClientHttpResponse> listenableFuture = execution.executeAsync(request, body);
            ListenableFutureAdapter<ClientHttpResponse,ClientHttpResponse> futureAdapter=
                    new ListenableFutureAdapter<ClientHttpResponse, ClientHttpResponse>(listenableFuture) {
                        @Override
                        protected ClientHttpResponse adapt(ClientHttpResponse adapteeResult) throws ExecutionException {
                            return logResponseBody(adapteeResult);
                        }
                    };
            return  futureAdapter;
        }

    private ClientHttpResponse logResponseBody(ClientHttpResponse response,boolean isImageInResponse){
                try {
                    BufferingClientHttpResponseWrapper responseWrapper = new BufferingClientHttpResponseWrapper(response);
                    REQ_RES_LOGGER.debug("Response Status Code :" + responseWrapper.getStatusCode().value());
                    REQ_RES_LOGGER.debug("Response Status Text :" + responseWrapper.getStatusText());
                    if (response != null && response.getBody() != null) {
                        String responseXml = IOUtils.toString(responseWrapper.getBody(), Charset.defaultCharset());
                        REQ_RES_LOGGER.debug(responseXml);
                    } else {
                        REQ_RES_LOGGER.debug("Empty Response Body");
                    }
                    return responseWrapper;
                }catch (IOException io){
                    REQ_RES_LOGGER.error("Unexpected Error ",io);
                    return response;
                }

        }
    }

1 个答案:

答案 0 :(得分:2)

我终于找到了使用这个类的方法。因为这是一个最终类,所以它只能在Springframework中使用。弹簧框架中有pull request用于此更改。我不确定何时将这个更改合并到框架中,但下面是将解决上述问题的类。如果我们想拦截请求和响应以进行日志记录,这些类将会很有用。

BufferingAsyncClientHttpRequestFactory

public class BufferingAsyncClientHttpRequestFactory extends 

BufferingClientHttpRequestFactory
        implements AsyncClientHttpRequestFactory {

    private final AsyncClientHttpRequestFactory requestFactory;
    /**
     * Create a buffering wrapper for the given {@link ClientHttpRequestFactory}.
     * @param requestFactory the target request factory to wrap
     */
    public BufferingAsyncClientHttpRequestFactory(AsyncClientHttpRequestFactory requestFactory) {
        super((ClientHttpRequestFactory) requestFactory);
        this.requestFactory=requestFactory;
    }


    /**
     * Indicates whether the request/response exchange for the given URI and method
     * should be buffered in memory.
     * <p>The default implementation returns {@code true} for all URIs and methods.
     * Subclasses can override this method to change this behavior.
     * @param uri the URI
     * @param httpMethod the method
     * @return {@code true} if the exchange should be buffered; {@code false} otherwise
     */

    @Override
    public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) throws IOException {
        AsyncClientHttpRequest request = requestFactory.createAsyncRequest(uri, httpMethod);
        if (shouldBuffer(uri, httpMethod)) {
            return new BufferingAsyncClientHttpRequestWrapper(request);
        }
        else {
            return request;
        }
    }

    protected boolean shouldBuffer(URI uri, HttpMethod httpMethod) {
        return true;
    }


}

BufferingAsyncClientHttpRequestWrapper.java

public class BufferingAsyncClientHttpRequestWrapper extends AbstractBufferingAsyncClientHttpRequest {

    private final AsyncClientHttpRequest request;

    public BufferingAsyncClientHttpRequestWrapper(AsyncClientHttpRequest asyncClientHttpRequest){
        this.request=asyncClientHttpRequest;
    }

    @Override
    public HttpMethod getMethod() {
        return this.request.getMethod();
    }

    @Override
    public URI getURI() {
        return this.request.getURI();
    }

    @Override
    protected ListenableFuture<ClientHttpResponse> executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        this.request.getHeaders().putAll(headers);
        if(bufferedOutput.length>0){
            StreamUtils.copy(bufferedOutput,this.request.getBody());
        }
        ListenableFuture<ClientHttpResponse> futureResponse = this.request.executeAsync();
        ListenableFutureAdapter<ClientHttpResponse,ClientHttpResponse> bufferedResponse =
                new ListenableFutureAdapter<ClientHttpResponse, ClientHttpResponse>(futureResponse) {
                    @Override
                    protected ClientHttpResponse adapt(ClientHttpResponse adapteeResult) throws ExecutionException {
                        return new BufferingClientHttpResponseWrapper(adapteeResult);
                    }
                };
        return bufferedResponse;
    }
}