一、为什么需要session和cookie呢?
源于web系统的发展和变迁。
1.1 web1.0
强调的是资源的共享。以早年在论坛浏览帖子为例,帖子和帖子之间是没有什么必要联系的。web1.0强调的是资源的共享。HTTP协议是无状态的,无状态是指协议对于事务处理没有记忆能力。前后没有关联。
1.2 web2.0
强调的是交互。交互意味着是有多步操作,请求和请求之间是有依赖存在的。引入了session和cookie机制是来实现状态的记录。
二、session和cookie的特征
session和cookie都是由服务器生成的,都是用来存储特定的值。是键值对应的,也就是说:
key | value |
---|---|
session | xxxxx |
cookie | xxxxx |
生成的步骤和方式,存储的信息不是服务器自发地去生成,而是我们用代码来控制。
2.1 session
由服务器生成后,存储在服务器上。SessionID会返回给客户端。
响应信息头:set-cookie
2.1.1 SessionID
一般来说,SessionID会以 类似于 cookie的方式返回给客户端(并不是说他是cookie,当然也不是session)。在客户端进程直接绑定,是不会存储在客户端机器上,而是写在内存中的。
SessionID是服务器用来识别、操作存储session值的对象的。可以理解为SessionID是一把用来识别session的钥匙。
在服务器端,session的存储方式有文件方式、数据库方式,SessionID就是用来识别这个文件的(文件名相关)、识别数据库的某一条记录。
2.1.2 session的生命周期
一般来说,session的生命周期受到三个因素影响:
①服务器对于session对象的保存的最大时间的设置。
②重新启动了服务器。
③调用Session的invalidate方法。
注:客户端进程关闭(一般指浏览器的tab页关闭),则客户端将会丢失sessionID,只对客户端自身有影响,对其它封包工具是没有影响。
注意:丢失的是sessionid,本身的session在服务器端还是在的。是因为sessionid以cookie的形式返回给客户端,而cookie的默认生命周期是浏览器会话期间,所以每次打开都会创建新的Sessionid,导致了session消失的假象。
解决方法:可以更改cookie的存活时长
2.2 cookie
由服务器生成后,返回给客户端,存储在客户端机器上。
客户端(浏览器)在发送请求的时候,会自动将存活(存活详见下方的生命周期)、可用的cookie封装在请求头中和请求一起发送。
响应信息头:Cookie
2.2.2 cookie的生命周期
可以把cookie的生命周期类比为非实名制的入场门票。入场门票有一个使用期限。
一般来说,cookie的生命周期受到两个因素的影响:
① cookie自身的存活时间。 是服务器生成cookie时去设定的。类比为在入场门票的有效期内都可以去使用。一般默认为浏览器回话期间。所以很多时候关闭浏览器,cookie也会消失。
②客户端是否保留cookie。只对客户端自身有影响,对其他封包工具没影响,比如对于同一个url,我在浏览器端将cookie删掉了,postman中保留,只要没超过cookie的存活时间,都是可以接着使用的。类比为:入场门票送了朋友,只要在有效期内,都是可以入场的。
三、安全性
cooke是存储在客户端的,是可见的,是可以改变的。
session是存储在服务器端的,是不可见的,是不可改变的。
四、实例演示
4.1 cookie
没有缓存机制的情况
在代码中添加cookie缓存机制,分别命名为username和test,二者的区别是生命周期不同(此处代码省略)
在登录验证部分生成了相应头信息set-cookie,而且test比username消失的早
接着返回上一级登录界面,登录页面请求头:Cookie
只要访问的是这个ip之下的,在存活时间内都会带着这部分cookie
4.2 session
在代码中增加生成session的部分, 一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建。
备注:如果请求中没有sessionID这个cookie值,则会去新建(随机)set-cookie,如果有,则会按照这个sessionID去检索session使用,但是读取不到的时候也会根据用户请求的sessionID去新建。
新建一个session为例:
因为已经创建了,所以会直接读取,不会再set-cookie
如果此时关闭浏览器tab页重新进行抓包,那么Sessionid部分将消失,因为tab页关闭相当于进程终止。
五、示例code
//登录的时候将值放入session中 硬性写入 保持对于不同的sessionid里面的值相同
@RequestMapping("login")
public JsonResult<User> login(String username, String password, HttpSession session) {
// 调用业务对象的方法执行登录,并获取返回值
User data = userService.login(username, password);
//登录成功后,将uid和username存入到HttpSession中
session.setAttribute("uid", data.getUid());
session.setAttribute("username", data.getUsername());
// 将以上返回值和状态码OK封装到响应结果中并返回
return new JsonResult<User>(OK, data);
}
//创建从session中获取值的方法
/**
* 从HttpSession对象中获取uid
* @param session HttpSession对象
* @return 当前登录的用户的id
*/
protected final Integer getUidFromSession(HttpSession session) {
return Integer.valueOf(session.getAttribute("uid").toString());
}
/**
* 从HttpSession对象中获取用户名
* @param session HttpSession对象
* @return 当前登录的用户名
*/
protected final String getUsernameFromSession(HttpSession session) {
return session.getAttribute("username").toString();
}
//调用方法
@RequestMapping("change_password")
public JsonResult<Void> changePassword(String oldPassword, String newPassword, HttpSession session) {
// 调用session.getAttribute("")获取uid和username
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
// 调用业务对象执行修改密码
userService.changePassword(uid, username, oldPassword, newPassword);
// 返回成功
return new JsonResult<Void>(OK);
}
六、参考资料
- Session机制详解 这篇我个人认为表述非常明确
- 视频课程 一般般 而且使用的php 对于抓包工具使用比较灵活,适合测开看。
- session什么时候被创建 讲了jsp和html在session创建过程中的区别。
- session是什么时候被创建 主要讲了jsp创建session
- java中session的用法与原理