ClientHttpResponse使用代理使getBody()方法可以多次获取输入流

小林QAQ
2022-09-12 / 0 评论 / 27 阅读
温馨提示:
本文最后更新于2022-09-12,若内容或图片失效,请留言反馈。

最近在工作的时候,遇到一个问题。由于监控需要,在调用交易时需要使用过滤器获取ClientHttpResponse中的响应报文体中的部分内容。使用getBody()方法获取到一个输入流,但是输入流是不可重复读的,所以导致如果在过滤器内获取该输入流,传到后面业务逻辑的ClientHttpResponse就没有内容了,所以在网上查询找到了使用代理方式实现ClientHttpResponse接口,实现getBody()方法每次都返回一个新的流。这里简单介绍一下方法,就不放实现效果了。

1.静态代理实现ClientHttpResponse接口,重写getBody()方法

private class ClientHttpResponseWrapper implements ClientHttpResponse {
        private ClientHttpResponse clientHttpResponse;
        private byte[] body;

        public ClientHttpResponseWrapper(ClientHttpResponse clientHttpResponse) {
            this.clientHttpResponse = clientHttpResponse;
        }

        @Override
        public HttpStatus getStatusCode() throws IOException {
            return this.clientHttpResponse.getStatusCode();
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return this.clientHttpResponse.getRawStatusCode();
        }

        @Override
        public String getStatusText() throws IOException {
            return this.clientHttpResponse.getStatusText();
        }

        @Override
        public void close() {
            this.clientHttpResponse.close();
        }

        /**
         * 缓存body每次返回一个新的输入流
         * @return
         * @throws IOException
         */
        @Override
        public InputStream getBody() throws IOException {
            if (Objects.isNull(this.body)) {
                this.body = StreamUtils.copyToByteArray(this.clientHttpResponse.getBody());
            }
            return new ByteArrayInputStream(this.body == null ? new byte[0] : this.body);
        }

        @Override
        public HttpHeaders getHeaders() {
            return this.clientHttpResponse.getHeaders();
        }
    }

2.动态代理

private static class ClientHttpResponseHandler implements InvocationHandler {
        private static final String methodName = "getBody";
        private ClientHttpResponse clientHttpResponse;
        private byte[] body;

        ClientHttpResponseHandler(ClientHttpResponse clientHttpResponse) {
            this.clientHttpResponse = clientHttpResponse;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (StringUtils.equals(methodName, method.getName())) {
                if (Objects.isNull(this.body)) {
                    this.body = StreamUtils.copyToByteArray(this.clientHttpResponse.getBody());
                }
                return new ByteArrayInputStream(this.body == null ? new byte[0] : this.body);
            }
            return method.invoke(this.clientHttpResponse, args);
        }
    }

原理就不细说了,就是在每次调用ClientHttpResponse.getBody()的时候返回一个新的输入流,这样就不会因为无法重复读取输入流而无法重复获取返回报文体了。