spring - 如何将 BufferingClientHttpResponseWrapper 与 HttpComponentsAsyncClientHttpRequestFactory 结合使用

标签 spring spring-boot

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

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;
                }

        }
    }

最佳答案

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

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;
    }
}

关于spring - 如何将 BufferingClientHttpResponseWrapper 与 HttpComponentsAsyncClientHttpRequestFactory 结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42309192/

相关文章:

java - Hibernate 映射理解

java - 使用 Spring Boot 的 RESTful API 中的循环依赖关系

java - 在 Spring Boot 应用程序中处理或抛出异常的最佳实践是什么?

java - 使用gradle加载命令行属性但找不到方法execSpec()

java - 如何找到用户 Springboot Jira API 的问题?

java - 使用多个表单在 View 上提交表单时出现 Spring "Neither BindingResult nor plain target object for bean name"错误

java - 带盐的 Spring Security 3 SHA-1

java - 在 @ResponseStatus 中使用多个值 HttpStatus

java - "AlreadyBuiltException: This object has already been built"构建时 "springSecurityFilterChain"

java - 为什么我的 Spring Boot starter 没有将它的依赖项带到项目中?