概念:
我们先要了解HTTP是无状态的Web服务器,什么是无状态呢?就像上面夏洛特烦恼中经典的一幕对话一样,一次对话完成后下一次对话完全不知道上一次对话发生了什么。随着网络的不断发展,比如电商中的购物车只有记住了用户的身份才能够执行接下来的一系列动作。所以此时就需要我们无状态的服务器记住一些事情。
Cookie:
那么Web服务器是如何记住一些事情呢?既然Web服务器记不住东西,那么我们就在外部想办法记住,相当于服务器给每个客户端都贴上了一个小纸条。上面记录了服务器给我们返回的一些信息。然后服务器看到这张小纸条就知道我们是谁了。那么Cookie是谁产生的呢?Cookies是由服务器产生的。接下来我们描述一下Cookie产生的过程。
1.浏览器第一次访问服务端时,服务器此时肯定不知道他的身份,所以创建一个独特的身份标识数据,格式为key=value,放入到Set-Cookie字段里,随着响应报文发给浏览器。
2.浏览器看到有Set-Cookie字段以后就知道这是服务器给的身份标识,于是就保存起来,下次请求时会自动将此key=value值放入到Cookie字段中发给服务端。
3.服务端收到请求报文后,发现Cookie字段中有值,就能根据此值识别用户的身份然后提供个性化的服务。
接下来我们利用cookie实现自动登录功能:
/**
* 目标:接收界面的登录参数,判断登录情况,以及是否勾选了10天内免登录
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//登录名称 密码 是否选中
String loginName = req.getParameter("loginName");
String passWord = req.getParameter("passWord");
String checked = req.getParameter("checked");
//2.判断登录是否成功了
if ("admin".equals(loginName)&&"123456".equals(passWord)){
//3.判断登录是否成功了
if (checked!=null){
//选中了
//创建cookie
Cookie loginNameCookie = new Cookie("login_name", loginName);
Cookie passWordCookie = new Cookie("pass_word", passWord);
loginNameCookie.setMaxAge(10*24*60*60);
passWordCookie.setMaxAge(10*24*60*60);
//把cookie放到响应中去,最终响应给浏览器
resp.addCookie(loginNameCookie);
resp.addCookie(passWordCookie);
}
//响应到登录界面去展示登录后的详情!
resp.sendRedirect(req.getContextPath()+"/success.html");
}else {
//登录失败了
resp.setContentType("text/html;charset=utf-8");
PrintWriter pw = resp.getWriter();
pw.print("<script>");
pw.print("alert('用户名或密码错误');");
pw.print("history.back();");
pw.print("</script>");
}
}
}
以下是前端页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>会员登录</title>
<script>
window.onload=function () {
//alert(getCookieValue
//登录名和密码填充到表单中去,然后出发表单提交即可自动登录
var loginName=getCookieValue("login_name")
var passWord=getCookieValue("pass_word")
//必须cookie中存在登录名和密码说明才需要自动登录
if (loginName!=null&&passWord!=null&&loginName!=''&&passWord!=''){
document.getElementById("loginName").value=loginName;
document.getElementById("passWord").value=passWord;
document.getElementById("loginForm").submit();
}
}
function getCookieValue(name) {
//js网页地址对应的cookie数据
var cookies=document.cookie;
var arrs=cookies.split(";")
//遍历这个数组
for (var i = 0; i < arrs.length; i++) {
var arr=arrs[i].trim();
//使用=隔开
var keyAndValue=arr.split("=");
if (keyAndValue[0]==name){
return keyAndValue[1];
}
}
}
</script>
</head>
<body>
<h3>用户登录</h3>
<form action="/loginCookie/login" method="post" id="loginForm">
用户名:<input type="text" name="loginName" id="loginName"><br>
密码:<input type="password" name="passWord" id="passWord"><br>
<!--如果勾上,值是等于on,如果没有勾,为空-->
<input type="checkbox" name="checked">十天内免登录<hr>
<input type="submit" value="登录">
<input type="reset" value="重置">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>你已经登录成功!</h3>
</body>
</html>
项目启动以后我们输入路径http://localhost:8080/session/index.html,然后查看发的请求。可以看到下面那张图使我们首次访问服务器时发送的请求,可以看到服务器返回的响应中有Set-Cookie字段。而里面的key=value值正是我们服务器中设置的值。
那么浏览器的Cookie是存放在哪呢?如果是使用的是Chrome浏览器的话,那么可以按照下面步骤。
在计算机打开Chrome
在右上角,一次点击更多图标->设置
在底部,点击高级
在隐私设置和安全性下方,点击网站设置
依次点击Cookie->查看所有Cookie和网站数据
然后可以根据域名进行搜索所管理的Cookie数据。所以是浏览器替你管理了Cookie的数据,如果此时你换成了Firefox等其他的浏览器,因为Cookie刚才是存储在Chrome里面的,所以服务器又蒙圈了,不知道你是谁,就会给Firefox再次贴上小纸条
说到这里,应该知道了Cookie就是服务器委托浏览器存储在客户端里的一些数据,而这些数据通常都会记录用户的关键识别信息。
Session
Cookie是存储在客户端方,Session是存储在服务端方,客户端只存储SessionId
在上面我们了解了什么是Cookie,既然浏览器已经通过Cookie实现了有状态这一需求,那么为什么又来了一个Session呢?这里我们想象一下,如果将账户的一些信息都存入Cookie中的话,一旦信息被拦截,那么我们所有的账户信息都会丢失掉。所以就出现了Session,在一次会话中将重要信息保存在Session中,浏览器只记录SessionId,一个SessionId对应一次会话请求。
这里我们写一个新的方法来测试Session是如何产生的,我们在请求参数中加上HttpSession session,然后再浏览器中输入http://localhost:8005/testSession进行访问可以看到在服务器的返回头中在Cookie中生成了一个SessionId。然后浏览器记住此SessionId下次访问时可以带着此Id,然后就能根据此Id找到存储在服务端的信息了。
此时我们访问路径http://localhost:8005/testGetSession,发现得到了我们上面存储在Session中的信息。那么Session什么时候过期呢?
客户端:和Cookie过期一致,如果没设置,默认是关了浏览器就没了,即再打开浏览器的时候初次请求头中是没有SessionId了。
服务端:服务端的过期是真的过期,即服务器端的Session存储的数据结构多久不可用了,默认是30分钟。
如何让浏览器关闭还可以再访问服务器上没有过期的信息?
答:将Cookie中的会话ID保存下来,并且设置过期时间。
以下是代码演示:
/**
* 目标:让JSESSIONID的存储周期长一点,这样可以保证即使关闭了浏览器,会话还是使用使用同一个
* 需求:在Demo04中设置JSESSIONID存储中分钟,在demo05获取会话数据
* JSESSIONID是由浏览器存储的,默认是关闭浏览器就结束了,所以可以控制一下存活时间,
* Session是由服务器存储的:延迟死亡
*/
@WebServlet("/session04")
public class Demo04Session extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取会话对象
HttpSession session = req.getSession();
session.setAttribute("product","加热马桶");
//让客户端标识会话的jsessionid的存活时间久一点
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setMaxAge(10*60);//10分钟
resp.addCookie(cookie);
}
}
@WebServlet("/session05")//获取session数据
public class Demo05Session extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String product = (String) session.getAttribute("product");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print("product="+product+"<br/>");
}
}
到这里大家应该对Session有一定的了解了,Session是存储在Tomcat的容器中,所以如果后端机器是多台的话,因此多个机器间是无法共享Session的。