1. 概述
本文将深入探讨 Java 网络编程中的底层操作,重点解析 Cookie 的使用技巧。Java 平台内置了强大的网络支持,核心功能集中在 java.net
包中:
import java.net.*;
2. HTTP Cookie
当客户端向服务器发送 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 管理框架,需要实现 CookiePolicy
和 CookieStore
:
CookiePolicy
:定义接受/拒绝 Cookie 的规则CookieStore
:负责 Cookie 的存储和检索
创建默认 CookieHandler
并设为系统默认的代码:
CookieManager cm = new CookieManager();
CookieHandler.setDefault(cm);
⚠️ 注意:默认 CookieStore
使用易失性内存(JVM 生命周期内有效),重启 JVM 后数据丢失。如需持久化存储,必须自定义实现。
默认的 CookiePolicy
是 CookiePolicy.ACCEPT_ORIGINAL_SERVER
,这意味着:
- ✅ 接受来自原始服务器的 Cookie
- ❌ 拒绝通过代理服务器收到的 Cookie
5. 自定义 CookieManager
我们可以通过自定义 CookiePolicy
或 CookieStore
(或两者)来增强 CookieManager
。
5.1 CookiePolicy
CookiePolicy
提供了三个预定义实现:
ACCEPT_ORIGINAL_SERVER
:仅接受原始服务器的 Cookie(默认)ACCEPT_ALL
:接受所有来源的 CookieACCEPT_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 对象(示例省略)
}
实现要点:
- 构造器中获取默认
CookieStore
引用 - 实现
Runnable
接口,添加 JVM 关闭钩子 - 关闭时执行
run()
方法持久化 Cookie - 启动时从持久化存储加载 Cookie
这种简单实现就能让默认 CookieStore
具备持久化能力。
6. 总结
本文系统讲解了 HTTP Cookie 在 Java 中的操作方式,展示了如何通过编程方式访问和操作 Cookie。核心要点:
CookieHandler
是 Cookie 管理的抽象基类CookieManager
提供了开箱即用的完整实现- 通过自定义
CookiePolicy
可灵活控制 Cookie 接受规则 - 自定义
CookieStore
能实现持久化存储需求
完整源代码及示例可在 GitHub 项目 中获取。