聊聊HttpClient的ResponseHandler

本文主要研究一下HttpClient的ResponseHandler

ResponseHandler

org/apache/http/client/ResponseHandler.java

复制代码
public interface ResponseHandler<T> {

    /**
     * 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;

}

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

AbstractResponseHandler

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

复制代码
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public abstract class AbstractResponseHandler<T> implements ResponseHandler<T> {

    /**
     * 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 (&gt;= 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;

}

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<String> {

    /**
     * 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);
    }

}

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

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

execute

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

复制代码
    @Override
    public <T> T execute(final HttpHost target, final HttpRequest request,
            final ResponseHandler<? extends T> 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();
        }
    }

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()。

相关推荐
q***33371 小时前
oracle 12c查看执行过的sql及当前正在执行的sql
java·sql·oracle
Y***h1875 小时前
第二章 Spring中的Bean
java·后端·spring
8***29315 小时前
解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域
java·前端·spring
CoderYanger5 小时前
优选算法-栈:67.基本计算器Ⅱ
java·开发语言·算法·leetcode·职场和发展·1024程序员节
q***06295 小时前
Tomcat的升级
java·tomcat
多多*5 小时前
Java复习 操作系统原理 计算机网络相关 2025年11月23日
java·开发语言·网络·算法·spring·microsoft·maven
青云交5 小时前
Java 大视界 -- Java 大数据在智能物流无人配送车路径规划与协同调度中的应用
java·spark·路径规划·大数据分析·智能物流·无人配送车·协同调度
d***81726 小时前
解决SpringBoot项目启动错误:找不到或无法加载主类
java·spring boot·后端
ᐇ9596 小时前
Java集合框架深度实战:构建智能教育管理与娱乐系统
java·开发语言·娱乐
听风吟丶7 小时前
MyBatis 深度实战:从基础映射到企业级性能优化
java·tomcat