1. 概述

本文将重点介绍如何使用 Apache HttpClient 发送自定义 Cookie

如果想深入了解 HttpClient 的其他高级用法,可以参考主教程

2.1. HttpClient 4.3+ 版本

在较新的 HttpClient 4.3+ 版本中,我们使用流畅的构建器 API 来构造和配置客户端。

首先创建一个 Cookie 存储并设置示例 Cookie:

BasicCookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234");
cookie.setDomain(".github.com");
cookie.setPath("/");
cookieStore.addCookie(cookie);

然后通过 setDefaultCookieStore() 方法在 HttpClient 上设置 Cookie 存储,并发送请求:

@Test
final void whenSettingCookiesOnTheHttpClient_thenCookieSentCorrectly() throws IOException {
    final BasicCookieStore cookieStore = new BasicCookieStore();
    final BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234");
    cookie.setDomain(".github.com");
    cookie.setAttribute("domain", "true");
    cookie.setPath("/");
    cookieStore.addCookie(cookie);
    final HttpGet request = new HttpGet("http://www.github.com");

    try (CloseableHttpClient client = HttpClientBuilder.create()
        .setDefaultCookieStore(cookieStore)
        .build();

        CloseableHttpResponse response = (CloseableHttpResponse) client
            .execute(request, new CustomHttpClientResponseHandler())) {
        assertThat(response.getCode(), equalTo(200));
    }
}

⚠️ 关键点:必须正确设置 Cookie 的 domain 属性——否则客户端将完全不会发送该 Cookie!

根据具体版本,可能还需要添加:

cookie.setAttribute("domain", "true");

2.2. HttpClient 4.3 之前版本

在旧版 HttpClient(4.3 之前)中,Cookie 存储直接设置在 HttpClient 上:

@Test
public void givenUsingDeprecatedApi_whenSettingCookiesOnTheHttpClient_thenCorrect() 
  throws ClientProtocolException, IOException {
    BasicCookieStore cookieStore = new BasicCookieStore();
    BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234");
    cookie.setDomain(".github.com");
    cookie.setPath("/");
    cookieStore.addCookie(cookie);
    DefaultHttpClient client = new DefaultHttpClient();
    client.setCookieStore(cookieStore);

    HttpGet request = new HttpGet("http://www.github.com");

    response = client.execute(request);
    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
}

除了客户端构建方式不同,其他与 4.3+ 版本无异。

如果不想全局配置 HttpClient,可以通过 HttpContext 为单个请求设置 Cookie:

@Test
final void whenSettingCookiesOnTheRequest_thenCorrect() throws IOException {
    final BasicCookieStore cookieStore = new BasicCookieStore();
    final BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", "1234");
    cookie.setDomain(".github.com");
    cookie.setAttribute("domain", "true");
    cookie.setPath("/");
    cookieStore.addCookie(cookie);
    final HttpGet request = new HttpGet("http://www.github.com");

    try (CloseableHttpClient client = HttpClientBuilder.create()
        .setDefaultCookieStore(cookieStore)
        .build();

        CloseableHttpResponse response = (CloseableHttpResponse) client
            .execute(request, new CustomHttpClientResponseHandler())) {
        assertThat(response.getCode(), equalTo(200));
    }
}

更底层的做法是直接在 HTTP 请求头中设置 Cookie:

@Test
final void whenSettingCookiesOnARequest_thenCorrect() throws IOException {
    final HttpGet request = new HttpGet("http://www.github.com");
    request.setHeader("Cookie", "JSESSIONID=1234");
    try (CloseableHttpClient client = HttpClients.createDefault();

        CloseableHttpResponse response = (CloseableHttpResponse) client
            .execute(request, new CustomHttpClientResponseHandler())) {
        assertThat(response.getCode(), equalTo(200));
    }
}

踩坑警告:这种方式比内置 Cookie 支持更容易出错。例如,这里我们完全没有设置 domain 属性——这是不正确的做法。

5. 总结

本文展示了如何使用 HttpClient 发送自定义的、用户可控的 Cookie

注意:这不同于让 HttpClient 自动处理服务器设置的 Cookie,而是在底层手动控制客户端行为。

所有示例代码可在 GitHub 项目 中找到。


原始标题:Apache HttpClient – Send Custom Cookie