Session 及其使用示例

原文:Session 详解,学习 Session,这篇文章就够了(包含底层分析和使用)

说明:下面介绍 Session,我们使用到了浏览器抓包,HTTP 的知识,如果不了解,请先简单了解下。HTTP 介绍,HTTP 请求,HTTP 响应。因为 Cookie 和 Session 是一对“好兄弟”,我们介绍 Session 也要使用到 Cookie,如果不清楚 Cookie,请查看 Cookie 详解

什么是 Session

Session 在网络应用中称为“会话控制”,是服务器为了保存用户状态而创建的一个特殊的对象。简而言之,Session 就是一个对象,用于存储信息。

Session 有什么用

我们先来想一个问题,这个问题就是我们在游览购物网站时,我们并没有登录,但是我们任然可以将商品加入购物车,并且进行查看,当我们退出浏览器后再打开浏览器进行查看时,购物车中依然有我们选择的商品,这该怎么实现呢?

当然,我们可以使用 Cookie,但是 Cookie 不能存放大量数据,这时,我们就需要一种新的技术,Session。Session 是存储于服务器端的特殊对象,服务器会为每一个浏览器(客户端)创建一个唯一的 Session。这个 Session 是服务器端共享,每个浏览器(客户端)独享的。我们可以在 Session 存储数据,实现数据共享。

这是 Session 的简单原理示意图

img

Session 类似于一个 Map,里面可以存放多个键值对,是以 key-value 进行存放的。key 必须是一个字符串,value 是一个对象。

Session 底层实现机制

Session 是每一个浏览器(客户端)所唯一的,这个是怎么实现的呢?其实,在访问一个网站时,在 HTTP 请求中往往会携带一个 Cookie,这个 Cookie 的名字是 JSESSIONID,这个 JSESSIONID 表示的就是 Session 的 id,这个是由服务器创建的,并且是唯一的。服务器在使用 Session 时,会根据 JSESSIONID 来进行不同操作,如下图所示:

img

当我们在服务端使用 Session 时,首先要获取 Session,这个 Session 是通过 JSESSIONID 进行获取。当然,这时就已经有好多种情况了。例如浏览器访问时没有携带 JSESSIONID,浏览器携带的 JSESSIONID 对应的 Session 不存在(或者失效)等情况。上面这个图就对服务器获取 Session 的一些情况进行了说明。

浏览器抓包进行查看

下面我创建了一个简单的服务器,服务端操作 Session,看浏览器中的 JSESSIONID 是如何进行携带的。我服务器的访问地址是 localhost:8080/cs/createSession, 最开始浏览器是没有 JSESSIONID 的 Cookie,而服务端要操作 Session,我们访问后看服务器返回什么。

这是我们抓包后看到的请求头

img

这是我们的响应头

img

我们发现如果浏览器访问服务器,如果没有携带 JSESSIONID,那么服务器就会创建一个 Session,并且把这个 Session 的 JSESSIONID 返回给浏览器。

下面,我们再次访问同样的地址,这次就会携带 JSESSIONID 了。

我们发送的请求头

img

我们抓包看见的响应头

img

我们发现,如果浏览器携带了 JSESSIONID,那么浏览器在访问时就会携带。而服务器在使用 Session 时,就会使用这个 JSESSIONID 的 Session。

当然,上面是正常情况,那就是服务器端有对应 JSESSIONID 的 Session,并且没有过期。下面,我把浏览器发送请求的 JSESSIONID 改 2 个字母,看浏览器请求和服务器返回的是什么。

请求头

img

响应头

img

这次,我们发现请求头和响应头都携带了 JSESSIONID,这是因为浏览器携带的 JSESSIONID 在服务器端并没有对应的 Session,或者 Session 已经过期了。所以服务器创建了一个新的 Session,并且把新的 JSESSIONID 返回给了浏览器。

通过 Session 底层实现机制和 HTTP 抓包查看 JSESSIONID,大家应该已经对 Session 的原理有了清晰的认识。下面我来介绍一下 Session 的常用方法(基于 Java)。

Session 常用方法

  • request.getSession():得到请求浏览器(客户端)对应的 Session。如果没有,那么就创建应该新的 Session。如果有那么就返回对应的 Session
  • setAttribute(String s, Object o):在 Session 存放属性
  • getAttribute(String s):从 Session 中得到 s 所对应的属性
  • removeAttribute(String s):从 Session 中删除 s 对应的属性
  • getId():得到 Session 所对应的 id
  • invalidate():使 Session 立即无效
  • setMaxInactiveInterval(int i):设置 Session 最大的有效时间。注意,这个有效时间是两次访问服务器所间隔的最大时间,如果超过最大的有效时间,那么这个 Session 就失效了。

Session 实例应用

我们利用 Session 来实现一个登录验证的功能。如果用户登录成功了,那么我们在 1 天内访问主页面就不需要登录了。我们利用 Session 进行实现。

我创建了一个 html 页面,2 个 servlet 来实现这次功能。代码如下:

html 页面

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
<base href="/cs/">
</head>
<body>
<form action="checkLogin" method="post">
用户名:<input type="text" name="username" /><br/>
密 码:<input type="password" name="password" /><br/>
<input type="submit" value="登录">
</form>
</body>
</html>

这个 html 就是一个简单的登录页面。

这个 Servlet 用于判断用户名和密码是否是我们规定的

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/checkLogin")
public class CheckServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//得到用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//判断用户名和密码是否为我们设置的密码
if (username.equals("tom") && password.equals("tom123")){
//得到 Session
HttpSession Session = request.getSession();
//设置最长访问间隔时间
Session.setMaxInactiveInterval(60*60*24);
//将用户名存入 Session
Session.setAttribute("username",username);
//重定向到主页面
response.sendRedirect(request.getContextPath()+"/mainPage");
}else {
//设置 MIME 类型和编码
response.setContentType("text/html;charset=utf-8");
//写回提示信息
PrintWriter writer = response.getWriter();
writer.write("<h1>账号或密码错误</h1>");
writer.write("<h3><a href='"+request.getContextPath()+"/login.html'>点击重新登录</a></h3>");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}

这个 Servlet 就是我们的主页面

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/mainPage")
public class MainServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应的 MIME 类型和编码
response.setContentType("text/html;charset=utf-8");
//得到 Session
HttpSession Session = request.getSession();
//取出用户名
Object username = Session.getAttribute("username");
PrintWriter writer = response.getWriter();
//判断用户名是否存在
if (username != null){
//在一天内登录过,无需再次登录
writer.write("<h1>用户:"+username+" 登录成功</h1>");
}else {
//没有登录,或者登录间隔大于 1 天。重定向到登陆界面
response.sendRedirect(request.getContextPath()+"/login.html");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}

代码测试

我们一来就直接访问主界面。

img

发现服务器发现我们没有登录,直接重定向到登录界面。下面我们来登录一下,输入我们设置的用户名和密码,分别是 tom 和 tom123

img

我们登录成功了,那么现在我们关闭浏览器,然后重新打开,并且直接访问主界面,看能否直接访问。

img

我们发现登录成功了,并没有重定向,因为我们已经登录过了嘛,一天之内都不需要重新登陆。我们的功能就实现了。

  • Cookie 保存在客户端,Session 保存在服务端
  • Cookie 作用于他所表示的 path 中(url 中要包含 path),范围较小。Session 代表客户端和服务器的一次会话过程,web 页面跳转时也可以共享数据,范围是本次会话,客户端关闭也不会消失。会持续到我们设置的 Session 生命周期结束(默认 30min)
  • 我们使用 Session 需要 Cookie 的配合。Cookie 用来携带 JSESSIONID
  • Cookie 存放的数据量较小,Session 可以存储更多的信息
  • Cookie 由于存放在客服端,相对于 Session 更不安全
  • 由于 Session 是存放于服务器的,当有很多客户端访问时,肯定会产生大量的 Session,这些 Session 会对服务端的性能造成影响

总结

Session 就是一个存储于服务器的特殊对象,通过 Session 可以实现数据共享,Session 有一个 JSESSIONID,这个是 Session 的唯一标识,使用它可以查找到 Session。Session 是会话级别的,对于每一个客户端来说是独享它所拥有的 Session 的,我们使用 Session 在进行页面跳转时,服务端可以利用 Session 进行数据共享。Session 由服务器进行控制。Session 的创建和销毁都是服务器进行管理的。服务器会为每一个客户端创建一个 Session。

posted @   Higurashi-kagome  阅读(69)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示