Cookie 与 Session
Cookie 与 Session
一、Cookie 详解
1.Cookie 是什么?
Cookie,是某些网站为了辨别用户身份,进行session跟踪而储存在用户本地终端上的数据,由用户客户端计算机暂时或永久保存的信息;
2.为什么使用Cookie?
由于
web程序是使用HTTP传输协议的,而HTTP协议属于无状态的协议,对于事务处理没有记忆能力;因此当后续处理需要前面的信息时就需要重新上传,这样就会导致每次连接传送的数据量增大了;
Cookie的出现就可以解决这一问题:
原理:
第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器将其保存在本地,当该用户发送第二次请求时 就会把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是那个了;
简单来讲cookie的工作原理就是:
给每个用户发放一个通行证,这样服务器就能通过通行证确认用户身份了;
3.Cookie 产生时间
Cookie的使用首先取决于用户(原因:浏览器可以禁用Cookie,同时服务端也可以不set-cookie;Cookie的两种保存方式:其1为浏览器将Cookie保存在内存中,其2为保存在客户端的硬盘上,之后每次HTTP请求浏览器都会将Cookie发送给服务端;
4.Cookie 生存周期
Cookie在生成时就会被指定一个Expire值,这就是Cookie的生存周期,在这个周期内Cookie有效,超出周期就会被清除;
5.Cookie 缺陷
数量受限制
表现在:
一个浏览器能创建的
Cookie数量最多不超过300个,且每个不能超过4KB,每个web站点能设置的Cookie总数不能超过20个;
安全性得不到保障:
表现在:存在跨站点脚本攻击
浏览器可以设置禁用Cookie:
6.Cookie 使用场景
基于Cookie 的缺陷,因此一般使用在:
- 对安全性要求不高;
- 不需要存储大量的数据;
- 主要用于客户端与服务器之间的状态保持;
二、Session 详解
1.什么是 Session
Session也称为会话机制,那什么是会话呢?
会话的本质:就是一个"哈希表", 存储了一些键值对结构,其中key就是令牌的ID(token/sessionId),value就是用户信息(用户信息可以根据需求灵活设计);
sessionId 和 token 就可以理解成是同一个东西的不同叫法;
流程为:
- 当用户登陆的时候, 服务器在
Session中新增一个新记录, 并把sessionId / token返回给客户端(例如通过HTTP响应中的Set-Cookie字段返回); - 客户端后续再给服务器发送请求的时候, 需要在请求中带上
sessionId/ token(例如通过HTTP请求中的Cookie字段带上); - 服务器收到请求之后, 根据请求中的
sessionId / token在Session信息中获取到对应的用户信息, 再进行后续操作;
2.Session 生命周期
根据需求设定,一般为半个小时(当你登陆一个服务器时,服务器返回给你一个sessionID,登陆成功后的半个小时之内没有对该服务器进行任何的HTTP请求,半个小时之后进行一次HTTP请求,就会提示你重新登陆);
三、涉及核心方法
HttpServletRequest 类中的相关方法:
| 方法 | 描述 |
|---|---|
| HttpSession getSession() | 在服务器中获取会话,参数为true,当会话不存在时,新建会话;参数为false时,会话不存在返回null |
| Cookie[] getCookies() | 返回一个数组,包含客户端发送请求的所有Cookie对象,会自动把Cookie中的格式解析成键值对 |
HttpServletResponse 类中的相关方法:
| 方法 | 描述 |
|---|---|
| void addCookie(Cookie cookie) | 把指定的Cookie 添加到响应中 |
HttpSession 类中的相关方法:
| 方法 | 描述 |
|---|---|
| Object getAttribute(String name) | 该方法返回在该 session 会话中具有指定名称的对象,没有返回null |
| void setAttribute(String name, Object value) | 该方法使用指定的名称绑定一个对象到该 session 会话 |
| boolean isNew() | 判定当前是否是新创建出的会话 |
Cookie 类中的相关方法:
| 方法 | 描述 |
|---|---|
| String getName() | 返回 cookie 的名称 ,名称在创建后不能改变,(这个值是 Set-Cooke 字段设置给浏览器的) |
| String getValue() | 获取与 cookie 关联的值 |
| void setValue(String newValue) | 设置与 cookie 关联的值 |
四、代码示例(用户登陆)
简单实现用户登陆,登陆成功后允许访问敏感资源:
前端代码:请求方法为 post
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>用户登陆</h3>
<form action="login" method="post">
<input type="text" name="username" placeholder="请输入用户名">
<br>
<input type="text" name="password" placeholder="请输入密码">
<br>
<input type="submit" value="提交">
</form>
</body>
</html>
后端代码:
- 创建一个
LoginServlet
package session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//body:username=xxx&password=xxx
//登陆成功:跳转到request.html,此时允许访问敏感资源(/sensitive)
//登陆失败:返回错误信息,此时不允许访问敏感资源
String username = req.getParameter("username");
String password = req.getParameter("password");
//模拟数据库进行账号密码登陆
if("abc".equals(username) && "123".equals(password)){
//登陆成功
//为登陆成功的用户创建一个session
//tomcat启动时维护了一个数据结Map<String,Session>
//用来保存多个用户的会话信息,键为sessionID的值(随机字符串)
//获取当前请求的session,如果没有获取到就重新创建一个放在Map结构中
HttpSession session =req.getSession(true);
//session对象本身也是一个Map结构,可以保存多组键值对的信息
session.setAttribute("u","username");
//以上代码会设置一个set-cookie,jsessionid=随机字符串
//跳转到登录后的页面
resp.sendRedirect("request.html");
}else{
//登陆失败,返回错误信息
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().println("登陆失败");
}
}
}
- 创建一个
SensitiveServlet
package session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/sensitive")
public class SensitiveServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//获取当次请求的session(此时可能登陆,也可能没有登陆)
//如果没有获取到,就返回null
HttpSession session = req.getSession(false);
if(session != null){
//session 不为空
String username = (String) session.getAttribute("u");
if(username != null){
//session设置的数据也不为空
resp.getWriter().println("用户已登陆,允许访问");
return;
}
}
resp.getWriter().println("用户未登录,不允许访问");
}
}
运行 tomcat,三种情况如下所示:
- (1)当没有登陆时就访问
sensitive,此时出现如下界面所示内容:

- (2)当访问登陆页面时,输入错误的账号密码时,如下所示:

当点击提交时,也面会发生跳转,但会显示如下登陆失败页面:

- (3)只有输入正确的账号密码时,页面才会跳转到
request.html中,显示:

服务器会给当前用户设置一个set-cookie,jsessionid=随机字符串:

五、小结
Cookie是客户端的机制,它可以存储在浏览器,也可以存储在本地;Session是服务器端的机制,只能存储在服务器;session能够存储任意的Java对象,但cookie只能存储string类型的对象;session占用服务器性能,session越多就会增加服务器压力;cookie没有session安全性高;- 单个
cookie保存的数据不能超过4KB,而session的大小限制与服务器本身的内存大小相关;