• 聊聊HttpClient的ResponseHandler


    本文主要研究一下HttpClient的ResponseHandler

    ResponseHandler

    org/apache/http/client/ResponseHandler.java

    public interface ResponseHandler {
    
        /**
         * Processes an {@link HttpResponse} and returns some value
         * corresponding to that response.
         *
         * @param response The response to process
         * @return A value determined by the response
         *
         * @throws ClientProtocolException in case of an http protocol error
         * @throws IOException in case of a problem or the connection was aborted
         */
        T handleResponse(HttpResponse response) throws ClientProtocolException, IOException;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ResponseHandler定义了handleResponse方法,用于解析HttpResponse到泛型T

    AbstractResponseHandler

    org/apache/http/impl/client/AbstractResponseHandler.java

    @Contract(threading = ThreadingBehavior.IMMUTABLE)
    public abstract class AbstractResponseHandler implements ResponseHandler {
    
        /**
         * Read the entity from the response body and pass it to the entity handler
         * method if the response was successful (a 2xx status code). If no response
         * body exists, this returns null. If the response was unsuccessful (>= 300
         * status code), throws an {@link HttpResponseException}.
         */
        @Override
        public T handleResponse(final HttpResponse response)
                throws HttpResponseException, IOException {
            final StatusLine statusLine = response.getStatusLine();
            final HttpEntity entity = response.getEntity();
            if (statusLine.getStatusCode() >= 300) {
                EntityUtils.consume(entity);
                throw new HttpResponseException(statusLine.getStatusCode(),
                        statusLine.getReasonPhrase());
            }
            return entity == null ? null : handleEntity(entity);
        }
    
        /**
         * Handle the response entity and transform it into the actual response
         * object.
         */
        public abstract T handleEntity(HttpEntity entity) throws IOException;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    AbstractResponseHandler声明实现ResponseHandler接口,其handleResponse方法针对statusCode大于等于300的抛出HttpResponseException,对于entity不为null的执行handleEntity方法

    BasicResponseHandler

    org/apache/http/impl/client/BasicResponseHandler.java

    @Contract(threading = ThreadingBehavior.IMMUTABLE)
    public class BasicResponseHandler extends AbstractResponseHandler {
    
        /**
         * Returns the entity as a body as a String.
         */
        @Override
        public String handleEntity(final HttpEntity entity) throws IOException {
            return EntityUtils.toString(entity);
        }
    
        @Override
        public String handleResponse(
                final HttpResponse response) throws HttpResponseException, IOException {
            return super.handleResponse(response);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    BasicResponseHandler继承了AbstractResponseHandler,它将entity转为String,使用的是EntityUtils.toString(entity)方法

    EntityUtils.toString

    org/apache/http/util/EntityUtils.java

        public static String toString(final HttpEntity entity) throws IOException, ParseException {
            Args.notNull(entity, "Entity");
            return toString(entity, ContentType.get(entity));
        }
    
        private static String toString(
                final HttpEntity entity,
                final ContentType contentType) throws IOException {
            final InputStream inStream = entity.getContent();
            if (inStream == null) {
                return null;
            }
            try {
                Args.check(entity.getContentLength() <= Integer.MAX_VALUE,
                        "HTTP entity too large to be buffered in memory");
                int capacity = (int)entity.getContentLength();
                if (capacity < 0) {
                    capacity = DEFAULT_BUFFER_SIZE;
                }
                Charset charset = null;
                if (contentType != null) {
                    charset = contentType.getCharset();
                    if (charset == null) {
                        final ContentType defaultContentType = ContentType.getByMimeType(contentType.getMimeType());
                        charset = defaultContentType != null ? defaultContentType.getCharset() : null;
                    }
                }
                if (charset == null) {
                    charset = HTTP.DEF_CONTENT_CHARSET;
                }
                final Reader reader = new InputStreamReader(inStream, charset);
                final CharArrayBuffer buffer = new CharArrayBuffer(capacity);
                final char[] tmp = new char[1024];
                int l;
                while((l = reader.read(tmp)) != -1) {
                    buffer.append(tmp, 0, l);
                }
                return buffer.toString();
            } finally {
                inStream.close();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    EntityUtils.toString方法通过entity.getContent()获取InputStream,之后将InputStream读取到CharArrayBuffer,最后关闭InputStream

    execute

    org/apache/http/impl/client/CloseableHttpClient.java

        @Override
        public  T execute(final HttpHost target, final HttpRequest request,
                final ResponseHandler responseHandler, final HttpContext context)
                throws IOException, ClientProtocolException {
            Args.notNull(responseHandler, "Response handler");
    
            final CloseableHttpResponse response = execute(target, request, context);
            try {
                final T result = responseHandler.handleResponse(response);
                final HttpEntity entity = response.getEntity();
                EntityUtils.consume(entity);
                return result;
            } catch (final ClientProtocolException t) {
                // Try to salvage the underlying connection in case of a protocol exception
                final HttpEntity entity = response.getEntity();
                try {
                    EntityUtils.consume(entity);
                } catch (final Exception t2) {
                    // Log this exception. The original exception is more
                    // important and will be thrown to the caller.
                    this.log.warn("Error consuming content after an exception.", t2);
                }
                throw t;
            } finally {
                response.close();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    CloseableHttpClient的execute方法先执行execute,然后try catch执行responseHandler.handleResponse,然后执行EntityUtils.consume(entity),在ClientProtocolException的时候也会执行EntityUtils.consume(entity),最后执行response.close()

    小结

    HttpClient提供了ResponseHandler接口,它有一个实现类是BasicResponseHandler,将entity的content转为string;相应的CloseableHttpClient也提供了支持ResponseHandler参数的execute方法,它先执行无handler的execute方法,然后try catch执行responseHandler.handleResponse,然后执行EntityUtils.consume(entity),在ClientProtocolException的时候也会执行EntityUtils.consume(entity),最后执行response.close()。

  • 相关阅读:
    Xftp 7过期后下载使用免费版
    数据分析1-matplotlib
    Flink+ice 实现可视化规则编排与灵活配置(Demo)
    spring boot 时间格式化输出
    如何做一个基于python校园排课选课系统毕业设计毕设作品(Django框架)
    文献 | 肥胖这种病,心理因素是源头?
    使用HTML+CSS技术制作篮球明星介绍网站
    私域流量对企业的好处
    数电票开错了能作废吗?百望云一次性说清数电票红冲全部问题
    【广度优先搜索】leetcode 994. 腐烂的橘子
  • 原文地址:https://blog.csdn.net/hello_ejb3/article/details/133714088