Simulating Multiple Simultaneous Logins with Apache HttpClient

This guide shows how to disable HttpClient's automatic cookie handling, manually extract and store Set‑Cookie headers, and bind cookies to individual user objects so that multi‑user, multi‑threaded API tests can simulate concurrent logins reliably.

FunTester
FunTester
FunTester
Simulating Multiple Simultaneous Logins with Apache HttpClient

When using Apache HttpClient for API testing, the default cookie manager interferes with scenarios that require multiple users to log in at the same time, because cookies are shared globally.

1. Disable automatic cookie management

Configure a RequestConfig that sets CookieSpecs.IGNORE_COOKIES and disables redirects. This prevents HttpClient from automatically storing or rejecting cookies.

private static RequestConfig getRequestConfig() {
    return RequestConfig.custom()
        .setConnectionRequestTimeout(HttpClientConstant.CONNECT_REQUEST_TIMEOUT)
        .setConnectTimeout(HttpClientConstant.CONNECT_TIMEOUT)
        .setSocketTimeout(HttpClientConstant.SOCKET_TIMEOUT)
        .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
        .setRedirectsEnabled(false)
        .build();
}

The same RequestConfig can be applied either to an HttpRequestBase instance or directly to a CloseableHttpClient. In practice the author injects it into a pooled CloseableHttpClient:

private static CloseableHttpClient getCloseableHttpsClients() {
    // Create a custom HTTPS client with the connection manager and the request config above
    CloseableHttpClient client = HttpClients.custom()
        .setConnectionManager(connManager)
        .setRetryHandler(httpRequestRetryHandler)
        .setDefaultRequestConfig(requestConfig)
        .build();
    return client;
}

2. Manually process Set‑Cookie headers

After receiving a response, the code extracts all Set-Cookie headers, splits each header value at the first semicolon and then at the first equals sign, and stores the name‑value pair in a JSONObject called cookies:

private static JSONObject afterResponse(CloseableHttpResponse response) {
    JSONObject cookies = new JSONObject();
    List<Header> headers = Arrays.asList(response.getHeaders("Set-Cookie"));
    if (headers.size() == 0) return cookies;
    headers.forEach(x -> {
        String[] split = x.getValue().split(";")[0].split("=", 2);
        cookies.put(split[0], split[1]);
    });
    return cookies;
}

If the response body is not valid JSON, the method falls back to wrapping the raw content and adds an error code, while still attaching any extracted cookies:

private static JSONObject getJsonResponse(String content, JSONObject cookies) {
    JSONObject jsonObject = new JSONObject();
    try {
        jsonObject = JSONObject.fromObject(content);
    } catch (Exception e) {
        jsonObject.put("content", content);
        jsonObject.put("code", TEST_ERROR_CODE);
        logger.warn("Response body is not JSON, automatically converted.");
    } finally {
        if (!cookies.isEmpty()) jsonObject.put(HttpClientConstant.COOKIE, cookies);
        return jsonObject;
    }
}

3. Store and reuse cookies per user

Each test object's base class keeps the latest cookie map after a response. When sending a new request, the code adds the common request ID, a token header, and, if present, a header containing the stored cookies:

public JSONObject getResponse(HttpRequestBase httpRequestBase) {
    setHeaders(httpRequestBase);
    JSONObject response = FanLibrary.getHttpResponse(httpRequestBase);
    handleResponseHeader(response);
    return response;
}

public void setHeaders(HttpRequestBase httpRequestBase) {
    httpRequestBase.addHeader(Common.REQUEST_ID);
    httpRequestBase.addHeader(FanLibrary.getHeader("token", token));
    if (!cookies.isEmpty()) httpRequestBase.addHeader(FanLibrary.getCookies(cookies));
}

public void handleResponseHeader(JSONObject response) {
    if (!response.containsKey(HttpClientConstant.COOKIE)) return;
    cookies.putAll(response.getJSONObject(HttpClientConstant.COOKIE));
    response.remove(HttpClientConstant.COOKIE);
}

Because the test framework runs many threads, the author observed occasional double‑initialisation of the base object, which could invalidate previously stored cookies. To avoid this, a thread‑bound user model is used: each thread represents a single user, ensuring that cookies are never mixed between users.

4. Practical considerations

The approach works for both HTTP and HTTPS protocols.

Disabling automatic cookie handling is essential; otherwise, HttpClient may reject cookies when the server sends a Set-Cookie header that does not match the default policy.

Storing cookies in a JSONObject keeps the data structure lightweight and easy to serialize.

Thread‑binding simplifies concurrency control without needing a complex notification system for cookie updates.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

multithreadingCookieAPI testingHttpClient
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.