一、认识Cookie/Session
- Cookie
Cookie是什么?
Cookie是服务器发送到用户浏览器并保存在本地的一小块数据。它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。Cookie主要用于:
- 会话管理:登录状态、购物车内容、游戏分数等
- 个性化:用户偏好、主题设置
- 跟踪:记录和分析用户行为
Cookie通常由服务器通过HTTP响应头中的
Set-Cookie字段设置,浏览器收到后会将其存储在本地,并在后续请求中通过Cookie请求头自动发送给服务器。
Cookie的工作原理:
- 客户端首次访问服务器:用户通过浏览器访问网站
- 服务器在响应头中设置Cookie:服务器生成Cookie并通过
Set-Cookie响应头发送给浏览器 - 浏览器保存这个Cookie:浏览器将Cookie存储在本地(内存或硬盘)
- 后续每次请求,浏览器自动在请求头中携带Cookie:浏览器向同一服务器发送请求时,会自动在
Cookie请求头中包含之前保存的Cookie - 服务器通过Cookie识别用户身份:服务器解析Cookie内容,识别用户身份和状态
- Session
Session是什么?
Session是服务器端的一种机制,用于在多次HTTP请求间保持用户状态。由于HTTP协议本身是无状态的,服务器需要一种方式来识别连续请求是否来自同一用户。Session机制通过在服务器端存储用户数据,并为每个用户分配一个唯一的Session ID来解决这个问题。
Session ID通常存储在Cookie中(也可以存储在URL中),浏览器每次请求时携带这个ID,服务器根据ID找到对应的Session数据。
Session的工作原理:
- 用户首次访问网站:服务器创建Session并生成唯一的Session ID
- 服务器将Session ID通过Cookie发送给浏览器:通过
Set-Cookie响应头将Session ID发送给客户端 - 浏览器后续请求携带这个Session ID:浏览器在Cookie中保存Session ID,并在后续请求中自动携带
- 服务器根据Session ID找到对应的Session数据:服务器通过Session ID从Session存储(内存、数据库等)中查找对应的用户数据
- 服务器可以读取、修改Session中的数据:如用户信息、购物车内容、登录状态等
Cookie 和 Session 的区别
- 存储位置不同:Cookie存储在客户端(浏览器),Session存储在服务器端
- 安全性不同:Session相对更安全,因为敏感数据存储在服务器端;Cookie存储在客户端,可能被篡改或窃取
- 存储容量不同:Cookie有大小限制(通常4KB),Session理论上可以存储更多数据
- 生命周期不同:Cookie可以设置过期时间,可以长期保存;Session通常有超时时间,关闭浏览器后可能失效
- 关联方式:Cookie和Session之间主要通过SessionId关联,SessionId是Cookie和Session之间的桥梁
- 使用关系:Cookie和Session经常在一起配合使用,但不是必须配合。可以用Cookie来保存一些数据在客户端,这些数据不一定是用户身份信息,也不一定是SessionId
- 传递方式:Session中的sessionId不一定非得通过Cookie/Set-Cookie传递,也可以通过URL参数等方式传递
举个栗子:淘宝购物流程
登录阶段:输入用户名密码,服务器验证成功后:创建Session并存储你的用户ID;服务器生成Session ID,通过Cookie发送给浏览器;浏览器保存这个Cookie
浏览商品:你点击商品详情页;浏览器自动在请求头中携带Cookie(包含Session ID);服务器通过Session ID找到你的Session,知道你是已登录用户;服务器返回商品页面,并记录你的浏览历史到Session中
加入购物车:你将商品A加入购物车;服务器将商品A信息存储在你的Session的购物车数据中
你继续浏览,将商品B也加入购物车;服务器更新Session中的购物车数据
结算支付:你去购物车页面;服务器从你的Session中读取购物车所有商品;你确认订单并支付
支付完成后,服务器清空Session中的购物车数据,但可能保留订单信息到数据库
💡 关键理解点:
- Cookie就像你的"会员卡号":每次消费时出示,商家通过卡号找到你的会员档案
- Session就像商家的"会员档案系统":存储你的消费记录、积分、购物车等信息
- 没有Cookie,服务器无法知道哪个Session属于你:Cookie携带Session ID,是连接客户端和服务器的桥梁
- 没有Session,Cookie只是一个无意义的ID:Cookie本身只存储标识信息,真正的用户数据存储在服务器的Session中
- 实际应用:现代Web应用中,Session数据通常存储在Redis等内存数据库中,以提高性能和可扩展性
这里的令牌就可理解为SessionId!!
二、获取Cookie
2.1 传统获取方式
@RequestMapping("/h11") public String method(HttpServletRequest request, HttpServletResponse response){ Cookie[] cookies= request.getCookies(); StringBuilder builder=new StringBuilder(); if(cookies!=null){ for(Cookie ck:cookies){ builder.append(ck.getName()+":"+ck.getValue()); } } return "Cookie信息"+builder; }此时由于我们没有设置Cookie,所以浏览器访问后得到Cooike值为null
手动设置一下Cookie值:
以上我们可以得知,Cookie也是可以伪造的,也就是不安全的。所以使用Cookie时,后端需要进行Cookie校验!
2.2 简洁获取方式
@RequestMapping("/h12") public String cookie(@CookieValue("hhh") String hhh){ return "h:"+hhh; }运行结果:
三、Session存储和获取
Session是服务器端的机制,我们需要先存储,才能获取
Session也是基于HttpServletRequest来存储和获取的
3.1 存储Session
@RequestMapping("h13") public String s(HttpServletRequest request){ //获取Session对象 HttpSession session=request.getSession(); if(session!=null){ session.setAttribute("username","java"); } return "session 存储成功"; }3.2 获取Session
获取Session有两种方式
- HttpSession getSession(boolean create);//参数如果为true,则当不存在会话时新建会话;参数如果为false,则当不存在会话时返回null
- HttpSession getSession( );
HttpSession getSession()和HttpSession getSession(true)含义一样,默认值为true;
void setAttribute(String name,Object value):使用指定的名称绑定一个对象到该session会话
方法一:
@RequestMapping("h14") public String s(HttpServletRequest request){ //如果session不存在,不会自动创建 HttpSession session= request.getSession(false); String username=null; if(session != null && session.getAttribute("username")!= null){ username=(String)session.getAttribute("username"); } return "username"+username; }方法二:
@RequestMapping("/h15") public String s(@SessionAttribute(value = "username",required = false) String username){ return "username"+username; }方法三:
@RequestMapping("/h16") public String s(HttpSession session){ String username=(String)session.getAttribute("username"); return "username"+username; }四、获取Header
方法一:
@RequestMapping("/h17") public String header(HttpServletRequest request,HttpServletResponse response) { String userAgent = request.getHeader("User-Agent"); String name = "测试用户"; return name+":"+userAgent; }方法二:
@RequestMapping("/h18") public String header(@RequestHeader("User-Agent") String userAgent){ return "userAgent:"+userAgent; }两种方式运行结果均为:
五、响应
5.1 返回静态页面(@Controller)
我们先创建一个前端页面
此时按照之前方法访问:
结果发现,页面并未正确返回,http响应把 "/index.html" 当做了http响应正文的数据,那Spring MVC如何才能识别出来 index.html 是⼀个静态页面呢?
需要把@RestController改为@Controller
前面使用的@RestController其实是返回数据的
@RestController=@Controller+@ResponseBody
@Controller:定义一个控制器,Spring框架启动加载时,把这个对象交给Spring管理。
@ResponseBody:定义返回的数据格式为非视图,返回一个text/html信息
5.2 返回数据(@ReponseBody)
@ResponseBody 既是类注解, 又是方法注解如果作用在类上,表示该类的所有方法,返回的都是数据;如果作用在方法上,表示该方法返回的是数据。也就是说: 在类上添加@ResponseBody就相当于在所有的方法上添加了@ResponseBody 注解如果⼀个类的方法里, 既有返回数据的, 又有返回页面的, 就把 @ResponseBody注解添加到对应的方法上即可.
5.3 返回HTML代码片段
@RequestMapping("/returnHtml") @ResponseBody public String returnHtml() { return "<h1>Hello,HTML~</h1>"; }使用Fiddler抓包工具可以看到
响应中Content-Type常见取值有以下几种:
- text/html:body数据格式为HTML
- text/css:body数据格式是CSS
- application/javascript:body数据格式是JavaScript
- application/json:body数据格式是JSON
5.4 返回JSON
Spring MVC也可返回JSON
六、小结
咋天天这么困呢,明明也睡了挺久的。难受难受真难受