1. 概述

本文将深入探讨 Java 网络编程中的底层操作,重点解析 Cookie 的使用技巧。Java 平台内置了强大的网络支持,核心功能集中在 java.net 包中:

import java.net.*;

当客户端向服务器发送 HTTP 请求并收到响应时,服务器默认会"忘记"这个客户端。下次客户端再次请求时,服务器会将其视为全新用户。

而 Cookie 的出现打破了这种无状态限制,使客户端与服务器之间能建立会话,让服务器可以跨多个请求-响应对记住客户端身份。

从本节开始,我们将学习如何在 Java 网络编程中利用 Cookie 增强客户端-服务器通信。java.net 包中处理 Cookie 的核心类是 CookieHandler,配套的辅助类/接口包括:

  • CookieManager
  • CookiePolicy
  • CookieStore
  • HttpCookie

3. CookieHandler 类

当我们与 http://baeldung.com(或其他使用 HTTP 协议的 URL)通信时,URL 对象会使用名为 HTTP 协议处理器的引擎。该处理器会检查系统中是否存在默认的 CookieHandler 实例。若存在,则调用它来管理状态。

因此,CookieHandler 类的核心作用是为 HTTP 协议处理器提供回调机制。

CookieHandler 是抽象类,提供两个关键方法:

  • getDefault():获取当前安装的 CookieHandler
  • setDefault(CookieHandler):设置自定义的 CookieHandler(系统级全局生效)

此外还有两个核心方法:

  • put(uri, responseHeaders):将响应中的 Cookie 保存到存储区(每次收到响应时调用)
  • get(uri, requestHeaders):从存储区获取 Cookie 并添加到请求头(发送请求前调用)

这些方法都需要在 CookieHandler 的具体实现类中完成。此时 CookieManager 类就派上用场了——它为大多数常见场景提供了完整的 CookieHandler 实现。

接下来两节,我们将分别探讨 CookieManager 的默认模式和自定义模式。

4. 默认的 CookieManager

要构建完整的 Cookie 管理框架,需要实现 CookiePolicyCookieStore

  • CookiePolicy:定义接受/拒绝 Cookie 的规则
  • CookieStore:负责 Cookie 的存储和检索

创建默认 CookieHandler 并设为系统默认的代码:

CookieManager cm = new CookieManager();
CookieHandler.setDefault(cm);

⚠️ 注意:默认 CookieStore 使用易失性内存(JVM 生命周期内有效),重启 JVM 后数据丢失。如需持久化存储,必须自定义实现。

默认的 CookiePolicyCookiePolicy.ACCEPT_ORIGINAL_SERVER,这意味着:

  • ✅ 接受来自原始服务器的 Cookie
  • ❌ 拒绝通过代理服务器收到的 Cookie

5. 自定义 CookieManager

我们可以通过自定义 CookiePolicyCookieStore(或两者)来增强 CookieManager

5.1 CookiePolicy

CookiePolicy 提供了三个预定义实现:

  • ACCEPT_ORIGINAL_SERVER:仅接受原始服务器的 Cookie(默认)
  • ACCEPT_ALL:接受所有来源的 Cookie
  • ACCEPT_NONE:拒绝所有 Cookie

修改当前策略的简单方式:

CookieManager cm = new CookieManager();
cm.setCookiePolicy(CookiePolicy.ACCEPT_ALL);

但更强大的方式是自定义策略。假设我们信任特定代理服务器(如 baeldung.com),希望同时接受来自它和原始服务器的 Cookie:

public class ProxyAcceptCookiePolicy implements CookiePolicy {
    private String acceptedProxy;

    public boolean shouldAccept(URI uri, HttpCookie cookie) {
        String host = InetAddress.getByName(uri.getHost())
          .getCanonicalHostName();
        if (HttpCookie.domainMatches(acceptedProxy, host)) {
            return true;
        }

        return CookiePolicy.ACCEPT_ORIGINAL_SERVER
          .shouldAccept(uri, cookie);
    }

    // 标准构造器
}

使用自定义策略:

CookieManager cm = new CookieManager();
cm.setCookiePolicy(new ProxyAcceptCookiePolicy("baeldung.com"));
CookieHandler.setDefault(cm);

这样 Cookie 处理器将同时接受原始服务器和 http://www.baeldung.com 的 Cookie。

5.2 CookieStore

CookieManager 在每次 HTTP 响应时将 Cookie 添加到 CookieStore,并在每次 HTTP 请求时从中检索 Cookie。

默认 CookieStore 实现的致命缺陷:

  • ❌ 无持久化能力(JVM 重启后数据丢失)

要实现持久化存储(类似硬盘功能),需要自定义存储机制。关键点:

  • 无法在创建后向 CookieManager 传入 CookieStore 实例
  • 只能在创建 CookieManager 时传入,或通过 new CookieManager().getCookieStore() 获取默认实例引用

持久化 CookieStore 实现示例:

public class PersistentCookieStore implements CookieStore, Runnable {
    private CookieStore store;

    public PersistentCookieStore() {
        store = new CookieManager().getCookieStore();
        // 从持久化存储反序列化 Cookie 到 store
        Runtime.getRuntime().addShutdownHook(new Thread(this));
    }

    @Override
    public void run() {
        // 将 Cookie 序列化到持久化存储
    }

    @Override
    public void add(URI uri, HttpCookie cookie) {
        store.add(uri, cookie);
    }
    
    // 其他方法委托给 store 对象(示例省略)
}

实现要点:

  1. 构造器中获取默认 CookieStore 引用
  2. 实现 Runnable 接口,添加 JVM 关闭钩子
  3. 关闭时执行 run() 方法持久化 Cookie
  4. 启动时从持久化存储加载 Cookie

这种简单实现就能让默认 CookieStore 具备持久化能力。

6. 总结

本文系统讲解了 HTTP Cookie 在 Java 中的操作方式,展示了如何通过编程方式访问和操作 Cookie。核心要点:

  • CookieHandler 是 Cookie 管理的抽象基类
  • CookieManager 提供了开箱即用的完整实现
  • 通过自定义 CookiePolicy 可灵活控制 Cookie 接受规则
  • 自定义 CookieStore 能实现持久化存储需求

完整源代码及示例可在 GitHub 项目 中获取。


原始标题:A Guide to HTTP Cookies in Java Baeldung

« 上一篇: Java URL编程指南
» 下一篇: Java 8 forEach介绍