Debug:获取自定义cookie为空的常见原因

简介: 1 场景在实现HandlerInterceptor接口的过程中,常用到HttpServletRequest的getCookies()方法,可以获取缓存的cookie数据。以下拦截器可以实现利用cookie实现自动登录基本思路:检查cookie在不在-检查cookie_username在不在-检查session中有没有用户-保持登录实现:import entity.User;import ser

1 场景

在实现HandlerInterceptor接口的过程中,常用到HttpServletRequest的getCookies()方法,可以获取缓存的cookie数据。

  • 以下拦截器可以实现利用cookie实现自动登录
  • 基本思路:检查cookie在不在-检查cookie_username在不在-检查session中有没有用户-保持登录
  • 实现:

import entity.User;
import service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Objects;


@Component
@Slf4j
public class LoginAdvice implements HandlerInterceptor {

    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.debug("拦截器生效.......");
        // 获取cookie
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            // 获取cookie的用户名
            String cookie_username = null;
            // 遍历cookie数组
            for (Cookie cookie : cookies) {
                if ("cookie_username".equals(cookie.getName())) {
                    // 获取cookie中的用户名
                    cookie_username = cookie.getValue();
                    break;
                }
            }
            // cookie_username非空
            if (cookie_username != null) {
                // 根据用户登录账号获取数据库中的用户信息
                User dbUser = userService.getUserByUserName(cookie_username);
                // 存在该用户
                if (dbUser != null) {
                    // 获取HttpSession对象
                    HttpSession session = request.getSession();
                    // session中是否存在该用户,如果为空,表示用户已经从session登出,但是cookie还在,需要做保持登录
                    User sessionUser = (User) session.getAttribute("userInfo");
                    if (sessionUser != null) {
                        // 检查sessionUser和数据库中的User是否一致
                        if (Objects.equals(sessionUser, dbUser)) {
                            // session中存在该用户,并且和数据库中的用户信息一致,通过拦截器
                            return true;
                        } else if (Objects.equals(sessionUser.getUserName(), dbUser.getUserName())) {
                            // 将用户保存到session中,实现保持登录
                            session.setAttribute("userInfo", dbUser);
                            return true;
                        }
                    } else {
                        // 将用户保存到session中,实现保持登录
                        session.setAttribute("userInfo", dbUser);
                        return true;
                    }
                }
            }
        }
        // 其他情况均作为不通过拦截器来处理
        return false;
    }
}

2 可能的原因

2.1 未设置cookie的存储路径

2.1.1 问题复现

// 新建cookie
Cookie cookie = new Cookie("cookie_username", userName);
// 有效期30天
cookie.setMaxAge(30 * 24 * 60 * 60);
// 写入cookie
httpServletResponse.addCookie(cookie)

2.1.2 原因

  • UA可能会从默认路径回传cookie
  • 上述代码未设置cookie的存储路径,可能会引起获取不到cookie的问题

2.1.2 解决方式

// 新建cookie
Cookie cookie = new Cookie("cookie_username", userName);
// 有效期30天
cookie.setMaxAge(30 * 24 * 60 * 60);
// 设定cookie写入的路径
cookie.setPath(httpServletRequest.getContextPath());
// 写入cookie
httpServletResponse.addCookie(cookie);
  •  在设置cookie之前需要设置cookie的存储路径

2.2 postman使用错误

2.2.1 问题复现

  • 使用postman发请求时,后端无法获取到cookie中的信息。
  • 发送请求的方式如下:

  • 点击send按钮发送请求。此时,cookies中的记录如下:

可以看到cookie是有记录的,User-Agent(UA)发送请求时,后端应获取到一致的结果。但实际上,以这种方式发送请求并不能让后端获取到cookie。

2.2.2 原因

cookie的工作过程: UA(通常是浏览器)收到响应报文,看到里面有 Set-Cookie,知道这是服务器给的身份标识,于是就保存起来,下次再请求的时候就自动把这个值放进 Cookie 字段里发给服务器。

上述动作是浏览器做的,因此按照2.1.1中的方式发送请求并不能使后端获取到cookie。

2.2.3 解决方式

代替浏览器做动作,手动将cookie放在请求头中。

按照上述方式向后端发送请求,就可以获取到cookie信息啦。

参考资料

HTTP协议笔记

什么是cookie

HTTP的报文结构

相关文章
|
小程序 开发者
小程序顶部自定义导航栏添加背景图的实现
小程序顶部自定义导航栏添加背景图的实现
322 0
|
Linux Perl
Linux技巧|Awk 比较运算符
在 Awk 中,使用比较运算符(如 >, <, ==, != 等)可方便地过滤文本和字符串。本文通过示例展示了如何处理食品购物清单,标记数量小于或等于 20 的商品。 Awk 语法 `expression { actions; }` 用于根据条件执行操作,如在满足条件的行末尾添加特殊标记。例如,`$3 <= 20 { printf "%s\t%s\n", $0,"TRUE" ; }` 会在数量小于或等于 20 的行后添加 "TRUE"。继续探索 Awk 的比较运算符以进行更复杂的文本处理。
|
SQL 数据库
nested exception is dm.jdbc.driver.DMException: 字符串截断
nested exception is dm.jdbc.driver.DMException: 字符串截断 问题处理
|
机器学习/深度学习 资源调度 自然语言处理
长短时记忆网络(LSTM)完整实战:从理论到PyTorch实战演示
长短时记忆网络(LSTM)完整实战:从理论到PyTorch实战演示
16032 0
|
9月前
|
数据可视化 算法 数据挖掘
Python量化投资实践:基于蒙特卡洛模拟的投资组合风险建模与分析
蒙特卡洛模拟是一种利用重复随机抽样解决确定性问题的计算方法,广泛应用于金融领域的不确定性建模和风险评估。本文介绍如何使用Python和EODHD API获取历史交易数据,通过模拟生成未来价格路径,分析投资风险与收益,包括VaR和CVaR计算,以辅助投资者制定合理决策。
476 15
|
12月前
|
数据采集 运维 数据挖掘
Pandas中的Rank用法:数据排序的高效工具
Pandas中的Rank用法:数据排序的高效工具
467 0
|
Java Linux 虚拟化
Docker 部署spring-boot项目(超详细 包括Docker详解、Docker常用指令整理等)
Docker 部署spring-boot项目(超详细 包括Docker详解、Docker常用指令整理等)
6456 2
|
JavaScript
【Mac用户必看】Autodesk EAGLE PCB设计全攻略:从安装到制造,解锁Mac上高效电子设计新纪元!
【8月更文挑战第2天】【PCB设计】Mac系统Autodesk EAGLE PCB使用入门教程
994 11
|
安全 Java 数据库
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(上)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)
258 0
|
机器学习/深度学习 资源调度 算法
主动学习(Active Learning)简介综述汇总以及主流技术方案
3.主动学习(Active Learning)简介综述汇总以及主流技术方案
主动学习(Active Learning)简介综述汇总以及主流技术方案