Building a Robust HTTP Client Utility with Apache HttpClient

Apache HttpClient is a sophisticated library under the Apache Jakarta Commons project designed to provide an efficient, up-to-date, and feature-rich client-side implementation for the HTTP protocol. It supports latest HTTP standards and recommendations, offering more flexibility than the basic java.net package. Although the original Commons HttpClient is now deprecated, it has been succeeded by the Apache HttpComponents project, which includes HttpClient and HttpCore modules with enhanced performance and extensibility.

HttpClient handles multiple HTTP methods: GET, POST, PUT, HEAD, DELETE, OPTIONS, etc.

Implementation Overview

Below is a reusable utility class that wraps HttpClient to handle common HTTP operations. The class is configured with sensible timeouts, connection pool settings, and cookie management.

Dependencies

Import the necessary HttpClient packages:

import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.SocketConfig;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.CodingErrorAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

Utility Class Code

public class HttpClientUtil {
    private static final int REQUEST_TIMEOUT = 20000;
    private static final int CONNECT_TIMEOUT = 20000;
    private static final int READ_TIMEOUT = 25000;
    private static final int MAX_POOL_SIZE = 100;
    private static final int MAX_PER_ROUTE = 50;
    private static final String UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";

    private static CloseableHttpClient client = null;
    private static ConnectionConfig connCfg = null;
    private static SocketConfig sockCfg = null;
    private static RequestConfig reqCfg = null;
    private static BasicCookieStore cookieJar = null;

    static {
        init();
    }

    private static void init() {
        connCfg = ConnectionConfig.custom()
                .setMalformedInputAction(CodingErrorAction.IGNORE)
                .setUnmappableInputAction(CodingErrorAction.IGNORE)
                .setCharset(Consts.UTF_8).build();

        sockCfg = SocketConfig.custom().setTcpNoDelay(true).build();

        reqCfg = RequestConfig.custom()
                .setConnectionRequestTimeout(REQUEST_TIMEOUT)
                .setConnectTimeout(CONNECT_TIMEOUT)
                .setSocketTimeout(READ_TIMEOUT)
                .build();

        cookieJar = new BasicCookieStore();

        client = HttpClients.custom()
                .setDefaultConnectionConfig(connCfg)
                .setDefaultSocketConfig(sockCfg)
                .setDefaultRequestConfig(reqCfg)
                .setDefaultCookieStore(cookieJar)
                .setUserAgent(UA)
                .setMaxConnTotal(MAX_POOL_SIZE)
                .setMaxConnPerRoute(MAX_PER_ROUTE)
                .build();
    }

    public static HttpResult get(String url, Map<String, String> params, Header[] headers, Cookie[] cookies, String charset) {
        HttpResult result = null;
        try {
            URIBuilder builder = new URIBuilder(url);
            if (params != null && !params.isEmpty()) {
                builder.addParameters(buildParams(params));
            }
            if (charset != null) {
                builder.setCharset(Charset.forName(charset));
            }
            URI uri = builder.build();

            HttpGet get = new HttpGet(uri);
            if (headers != null) {
                get.setHeaders(headers);
            }
            if (cookies != null) {
                get.setHeader("Cookie", concatCookies(cookies));
            }

            result = client.execute(get, responseHandler());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static HttpResult postForm(String url, Map<String, String> formData, Header[] headers, Cookie[] cookies, String charset) {
        HttpResult result = null;
        try {
            HttpPost post = new HttpPost(url);
            if (formData != null && !formData.isEmpty()) {
                post.setEntity(buildFormEntity(formData, charset));
            }
            if (headers != null) {
                post.setHeaders(headers);
            }
            if (cookies != null) {
                post.setHeader("Cookie", concatCookies(cookies));
            }
            result = client.execute(post, responseHandler());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static HttpResult postJson(String url, String jsonPayload, Header[] headers, String charset) {
        HttpResult result = null;
        try {
            HttpPost post = new HttpPost(url);
            post.setEntity(buildJsonEntity(jsonPayload, charset));
            if (headers != null) {
                post.setHeaders(headers);
            }
            result = client.execute(post, responseHandler());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private static ResponseHandler<HttpResult> responseHandler() {
        return response -> {
            if (response == null) throw new ClientProtocolException("Null response");
            if (response.getStatusLine() == null) throw new ClientProtocolException("No status line");
            if (response.getStatusLine().getStatusCode() != 200)
                throw new HttpResponseException(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
            if (response.getEntity() == null) throw new ClientProtocolException("No entity");

            HttpResult r = new HttpResult();
            r.setStatusCode(response.getStatusLine().getStatusCode());
            ContentType ct = ContentType.getOrDefault(response.getEntity());
            r.setContentType(ct.toString());
            boolean isText = isTextResponse(ct);
            r.setTextType(isText);
            if (isText) {
                r.setTextContent(EntityUtils.toString(response.getEntity()));
            } else {
                r.setBytes(EntityUtils.toByteArray(response.getEntity()));
            }
            r.setHeaders(response.getAllHeaders());
            return r;
        };
    }

    private static List<NameValuePair> buildParams(Map<String, String> map) {
        List<NameValuePair> list = new ArrayList<>();
        if (map != null) {
            map.forEach((k, v) -> list.add(new BasicNameValuePair(k, v)));
        }
        return list;
    }

    private static UrlEncodedFormEntity buildFormEntity(Map<String, String> data, String charset) {
        return new UrlEncodedFormEntity(buildParams(data), charset != null ? charset : "UTF-8");
    }

    private static StringEntity buildJsonEntity(String json, String charset) {
        if (json == null || json.isEmpty()) json = "{}";
        StringEntity e = new StringEntity(json, ContentType.APPLICATION_JSON);
        if (charset != null) e.setContentEncoding(charset);
        return e;
    }

    private static String concatCookies(Cookie[] cookies) {
        StringBuilder sb = new StringBuilder();
        if (cookies != null) {
            for (Cookie c : cookies) {
                sb.append(c.getName()).append("=").append(c.getValue()).append(";");
            }
        }
        return sb.toString();
    }

    private static boolean isTextResponse(ContentType ct) {
        String mime = ct.getMimeType();
        if (mime.startsWith("text")) return true;
        if (mime.startsWith("image")) return false;
        if (mime.startsWith("application")) return mime.contains("json") || mime.contains("xml");
        if (mime.startsWith("multipart")) return false;
        return true;
    }
}

Response Wrapper Class

public class HttpResult {
    private Header[] headers;
    private int statusCode;
    private String contentType;
    private boolean textType;
    private String textContent;
    private byte[] bytes;

    // getters and setters omitted for brevity
}

Example Usage

HttpResult response = HttpClientUtil.postJson("https://api.example.com/endpoint", jsonParams.toString(), customHeaders(), "UTF-8");

Tags: Apache HttpClient Java HTTP client HttpComponents HTTP utility class CloseableHttpClient

Posted on Sat, 16 May 2026 05:36:33 +0000 by willchoong