什么是 Cookie?
Cookie 是一种在客户端(浏览器)存储小块数据(通常为 4KB 左右)的技术,它由服务器生成,发送给浏览器,浏览器会将其保存起来,之后,浏览器每次向同一服务器发起请求时,都会自动携带这些 Cookie。

可以把 Cookie 想象成服务器发给客户端的“会员卡”或“身份证”,客户端每次访问服务器时,都自动出示这张“卡”,服务器通过识别这张“卡”来辨认用户,或者记住用户的一些设置。
Cookie 的工作流程
Cookie 的工作流程非常简单,基于 HTTP 协议的无状态特性来增加状态:
- 客户端首次请求:浏览器访问一个网站(
www.example.com/login)。 - 服务器响应:服务器验证用户名和密码成功后,会创建一个 Cookie 对象(
JSESSIONID=xxxxxx),并通过Set-Cookie响应头发送给浏览器。 - 浏览器存储:浏览器接收到这个响应头后,会解析
Set-Cookie并将 Cookie 存储在本地。 - 后续请求:浏览器再次向
www.example.com的任何资源(如/home,/profile)发起请求时,会自动在请求头中带上Cookie头,格式为Cookie: JSESSIONID=xxxxxx。 - 服务器识别:服务器从请求头中读取
Cookie,从而识别出是哪个用户,并可以据此提供个性化的服务(如显示用户名、保持登录状态等)。
在 Java Web 中如何操作 Cookie?
在 Java Web 中,我们主要通过 Servlet API 来操作 Cookie,下面我们分步讲解。
创建和发送 Cookie(服务器 -> 客户端)
在 Servlet 中,通过 response 对象来创建并发送 Cookie。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/createCookie")
public class CreateCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 创建一个 Cookie 对象
// 参数1: Cookie 的名称 (name)
// 参数2: Cookie 的值 (value)
Cookie usernameCookie = new Cookie("username", "john_doe");
// 2. (可选) 设置 Cookie 的属性
// 设置 Cookie 的有效期,单位为秒,如果设置为0,则删除Cookie。
// 如果不设置,Cookie 会在浏览器关闭后失效(会话 Cookie)。
usernameCookie.setMaxAge(60 * 60 * 24); // 有效期为1天
// 设置 Cookie 的路径,只有访问该路径及其子路径时,浏览器才会携带此 Cookie。
// 设置为 "/myapp",则只有访问 /myapp/xxx 时才会携带。
// 如果不设置,默认是当前 Servlet 的路径。
usernameCookie.setPath("/");
// 3. 将 Cookie 添加到响应对象中
// 这一步会向客户端发送 "Set-Cookie" 响应头
resp.addCookie(usernameCookie);
// 4. 给用户一个反馈
resp.getWriter().write("Cookie 'username' has been created for you!");
}
}
读取 Cookie(客户端 -> 服务器)
在 Servlet 中,通过 request 对象来读取客户端发送过来的所有 Cookie。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/readCookie")
public class ReadCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 从 request 对象中获取所有 Cookie
Cookie[] cookies = req.getCookies();
// 2. 检查是否存在 Cookie
if (cookies != null) {
for (Cookie cookie : cookies) {
// 3. 获取 Cookie 的名称和值
String name = cookie.getName();
String value = cookie.getValue();
// 我们只查找名为 "username" 的 Cookie
if ("username".equals(name)) {
resp.getWriter().write("Welcome back, " + value + "!");
return; // 找到后直接返回
}
}
}
// 如果没有找到任何 Cookie 或目标 Cookie
resp.getWriter().write("No 'username' cookie found. Please log in first.");
}
}
删除 Cookie
删除 Cookie 并没有一个专门的 removeCookie() 方法,它的原理是:创建一个同名、同路径、有效期(maxAge)为 0 的 Cookie,并发送给客户端,浏览器会覆盖掉旧的 Cookie,并因为其已过期而立即删除它。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/deleteCookie")
public class DeleteCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 创建一个与要删除的 Cookie 同名的 Cookie 对象
Cookie usernameCookie = new Cookie("username", "");
// 2. 设置有效期为 0,这是关键!
// 这会告诉浏览器:“这个 Cookie 已经过期了,请立即删除它。”
usernameCookie.setMaxAge(0);
// 3. 设置路径,必须与创建时设置的路径完全一致,才能成功删除
usernameCookie.setPath("/");
// 4. 将 Cookie 添加到响应中
resp.addCookie(usernameCookie);
resp.getWriter().write("Cookie 'username' has been deleted.");
}
}
Cookie 的常用属性
| 属性 | 方法 | 描述 |
|---|---|---|
| Name | new Cookie(name, value) |
Cookie 的唯一标识符,创建后不可修改。 |
| Value | new Cookie(name, value) |
Cookie 的值,注意:不能包含空格、逗号、分号等特殊字符。 |
| Max-Age | setMaxAge(int seconds) |
Cookie 的生命周期(秒),如果为正数,表示在指定的秒数后过期;如果为 0,则立即删除;如果为负数(默认值),表示是“会话 Cookie”,浏览器关闭即失效。 |
| Path | setPath(String uri) |
指定 Cookie 的有效路径,只有请求的 URL 匹配该路径或其子路径时,浏览器才会携带此 Cookie。/app 会匹配 /app/user 和 /app/order。 |
| Domain | setDomain(String pattern) |
指定 Cookie 的有效域名,设置为 .example.com,则 www.example.com 和 store.example.com 都可以访问此 Cookie,默认为当前服务器的域名。 |
| Secure | setSecure(boolean flag) |
如果为 true,则只有通过 HTTPS(加密)协议连接时,才会将 Cookie 发送到服务器,用于保护敏感数据。 |
| HttpOnly | setHttpOnly(boolean flag) |
如果为 true,则禁止 JavaScript 通过 document.cookie 访问此 Cookie,这是防止 XSS(跨站脚本攻击)窃取 Cookie的重要手段。 |
Cookie 的优缺点与安全考量
优点
- 简单易用:API 简单,在所有浏览器中都得到支持。
- 状态保持:能够很好地弥补 HTTP 协议无状态的缺陷。
- 服务器端压力小:数据存储在客户端,不占用服务器资源。
缺点
- 存储容量小:单个 Cookie 通常限制在 4KB 左右,一个域名下最多约 20 个。
- 安全性较低:
- 明文传输:默认情况下,Cookie 是明文传输的,容易被窃取,应尽量配合 HTTPS 使用。
- XSS 攻击:Cookie 没有设置
HttpOnly,恶意脚本可以读取并窃取用户的 Cookie。 - CSRF 攻击:攻击者可以诱骗用户在已登录的网站上执行一个恶意请求,浏览器会自动带上用户的 Cookie,从而冒充用户执行操作。
- 性能开销:每次 HTTP 请求都会携带所有相关的 Cookie,增加了网络请求的大小。
- 用户隐私:用户可以在浏览器设置中禁用 Cookie,导致功能失效。
安全最佳实践
- 标记为
HttpOnly:对于任何用于认证的 Session ID 或敏感信息,必须设置HttpOnly为true。cookie.setHttpOnly(true);
- 使用
Secure属性:对于任何敏感的 Cookie,应设置Secure为true,确保其只在 HTTPS 连接下传输。cookie.setSecure(true); // 注意:这要求你的应用运行在 HTTPS 下
- 不要存储敏感信息:绝对不要在 Cookie 中存储密码、信用卡号等高度敏感的信息,Cookie 应该只存储不敏感的标识符(如 Session ID)或用户偏好设置。
- 设置合理的
Path和Max-Age:遵循最小权限原则,将Path设置得尽可能具体,避免不必要的 Cookie 被发送,为非会话 Cookie 设置合理的Max-Age。
Cookie vs. Session
在 Java Web 开发中,Cookie 和 Session 是两个紧密相关但又截然不同的概念。
| 特性 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端(浏览器) | 服务器端 |
少量文本数据(如 JSESSIONID=xxx) |
任意类型和数量的 Java 对象(通过 setAttribute 设置) |
|
| 安全性 | 较低,易被窃取和篡改 | 较高,数据在服务器端,客户端只持有 ID |
| 生命周期 | 可通过 setMaxAge 设置,可长期存在 |
通常与用户会话绑定,会话超时则失效 |
| 依赖性 | 不依赖 Session | 通常依赖 Cookie(通过 Cookie 传递 Session ID) |

- Session 是服务器用来保存用户状态的“保险箱”。
- Cookie 是发给用户,让用户每次访问时都能找到“保险箱钥匙”(即 Session ID)的“钥匙扣”。
当用户禁用 Cookie 时,Session 机制可能会失效(除非使用 URL 重写等其他技术),这体现了 Cookie 在 Session 管理中的基础性作用。
Cookie 是 Java Web 开发中一项基础且重要的技术,它简单、高效,用于实现用户认证、个性化设置等功能,由于其固有的安全风险,在使用时必须格外小心,始终遵循安全最佳实践,特别是为敏感 Cookie 设置 HttpOnly 和 Secure 属性,在现代 Web 开发中,虽然有 LocalStorage、SessionStorage 等客户端存储方案,但 Cookie 在处理会话管理(Session)和跨域认证等方面仍然扮演着不可替代的角色。
