文档首页> Linux命令> HttpServletRequest的Cookie的设置

HttpServletRequest的Cookie的设置

发布时间:2025-09-05 00:02       

使用 HttpServletRequest 读取 Cookie、以及正确设置/删除 Cookie(Servlet 原生做法)

先把关键点说清楚 ✅:

  • 读取:用 HttpServletRequest#getCookies()(只读,可能为 null)。
  • 设置/删除:用 HttpServletResponse#addCookie(Cookie)(服务端下发给浏览器)。HttpServletRequest 本身不能设置 Cookie。

一、设置 Cookie(安全属性齐全)🍪

// 伪代码:在 doPost/doGet 中
String sid = URLEncoder.encode(token, StandardCharsets.UTF_8); // 避免特殊字符
Cookie c = new Cookie("sid", sid);

// 基础属性
c.setPath("/");                    // 推荐设为根,避免子路径不可见
c.setMaxAge(7 * 24 * 3600);       // 7 天;会话 Cookie 用 -1
// 可选:跨子域共享(如 a.example.com 与 b.example.com)
c.setDomain("example.com");       // 不设则为 host-only,仅当前主机可见

// 安全属性
c.setHttpOnly(true);              // 禁止 JS 读取,防 XSS
c.setSecure(request.isSecure());  // 仅在 HTTPS 下发送
response.addCookie(c);

解释

  • URLEncoder 让值只含安全字符(也可用 Base64)。
  • HttpOnly/Secure 是生产必备 🔐。
  • 默认 Path 若不设置,会按规范取当前请求路径的父路径,容易出现别的路径拿不到 Cookie 的现象,显式设置为 / 最稳。

关于 SameSite(强烈建议设置)

Servlet 原生 Cookie尚未内置 SameSite 属性(不同容器支持进度不一)。通用做法:手动构造 Set-Cookie 头(只构造一次,不再调用 addCookie 以免重复)。

String value = URLEncoder.encode(token, StandardCharsets.UTF_8);
String header = "sid=" + value
    + "; Max-Age=" + (7 * 24 * 3600)
    + "; Path=/"
    + "; HttpOnly"
    + "; Secure"                 // 若 SameSite=None,必须同时 Secure
    + "; SameSite=None";         // 备选:Lax / Strict
response.addHeader("Set-Cookie", header);

选择建议

  • SameSite=Lax:大多数站点登录态够用,能减少 CSRF。
  • SameSite=None; Secure跨站场景(如嵌入 iframe、跨站回调)必需。
  • Strict:最安全,但跨站返回时不带 Cookie。

二、读取 Cookie(判空与解码)🔎

public static Optional<String> readCookie(HttpServletRequest request, String name) {
    Cookie[] arr = request.getCookies();
    if (arr == null) return Optional.empty();       // 可能为 null
    for (Cookie ck : arr) {
        if (name.equals(ck.getName())) {
            String val = URLDecoder.decode(ck.getValue(), StandardCharsets.UTF_8);
            return Optional.ofNullable(val);
        }
    }
    return Optional.empty();
}

解释

  • getCookies() 可能返回 null,必须判空。
  • 读取时与写入保持同一编码方式(URLDecoder 对应 URLEncoder)。
  • 如果设置了 Domain/Path,浏览器只会在符合作用域的请求里回传,其他请求上自然读不到。

三、更新与删除(务必匹配作用域)🧹

更新:与设置相同,同名 Cookie 再发一次即可覆盖(浏览器以最后一个为准)。
删除:必须 匹配原来的 Path 与 Domain,再把 Max-Age 设为 0

Cookie del = new Cookie("sid", "");
del.setPath("/");                 // 与原 Cookie 一致
// 若曾设置过 Domain,也要一致:del.setDomain("example.com");
del.setMaxAge(0);                 // 立即过期
del.setHttpOnly(true);
del.setSecure(true);
response.addCookie(del);

解释

  • 作用域不同等同于“另一个”Cookie,浏览器不会删对。
  • 删除也建议带上 HttpOnly/Secure,有些客户端对属性敏感,保持一致更稳妥。

四、常见坑与对策(速查表)📚

问题/现象 根因 对策
本地能读,子路径/子域读不到 Path/Domain 作用域不一致 Path 统一设为 /;需要跨子域就设 Domain=example.com
跨站场景不带 Cookie SameSite 默认限制 用 SameSite=None; Secure
JS 能读到敏感 Cookie 未设 HttpOnly 登录态/敏感信息一律 HttpOnly
HTTP 下 Cookie 不传 设置了 Secure 开发环境用 HTTPS 或临时去掉 Secure(生产必须启用)
值出现乱码或分号等非法字符 未编码 使用 URLEncoder或 Base64
删除失败 Path/Domain 不匹配 用与创建时完全一致的 Path/Domain 删除
过多/过大 浏览器有数量/体积限制(单个约 4KB 量级) 精简内容,改存服务器会话,Cookie 放 key/指针

五、最小可用模板(登录态示例)🚀

// 写入
void writeSid(HttpServletRequest req, HttpServletResponse resp, String token) {
    String v = URLEncoder.encode(token, StandardCharsets.UTF_8);
    // 这里示例:SameSite=Lax,更安全的默认
    String header = "sid=" + v + "; Max-Age=" + (7*24*3600) + "; Path=/; HttpOnly; Secure; SameSite=Lax";
    resp.addHeader("Set-Cookie", header);
}

// 读取
Optional<String> sid(HttpServletRequest req) {
    return readCookie(req, "sid");
}

// 删除
void removeSid(HttpServletResponse resp) {
    Cookie del = new Cookie("sid", "");
    del.setPath("/");
    del.setMaxAge(0);
    del.setHttpOnly(true);
    del.setSecure(true);
    resp.addCookie(del);
}