JavaWeb会话与状态管理之Session机制
阅读原文时间:2021年04月20日阅读:1

Session机制

  • session机制采用的是在服务器端保存 HTTP 状态信息的方案 。
  • 服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
  • 当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否包含了一个session标识(即sessionId),如果已经包含一个sessionId则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。如果客户请求不包含sessionId,则为此客户创建一个session并且生成一个与此session相关联的sessionId,这个session id将在本次响应中返回给客户端保存。

session.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" session="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <%= session.getId() %>
</body>
</html>

第一次请求,服务端会给客户端浏览器一个JSESSIONID

第二次请求客户端浏览器会把cookie带回去

Session cookie

  • session通过SessionID来区分不同的客户, session是以cookie或URL重写为基础的,默认使用cookie来实现,系统会创造一个名为JSESSIONID的输出cookie,这称之为session cookie,以区别persistent cookies(也就是我们通常所说的cookie),session cookie是存储于浏览器内存中的,并不是写到硬盘上的,通常看不到JSESSIONID,但是当把浏览器的cookie禁止后,web服务器会采用URL重写的方式传递Sessionid,这时地址栏看到
  • session cookie针对某一次会话而言,会话结束session cookie也就随着消失了,而persistent cookie只是存在于客户端硬盘上的一段文本。
  • 关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。

持久化的cookie,保存20s ,关掉浏览器还会有。

<%= session.getId() %>

<% 
    Cookie cookie = new Cookie("JSESSIONID", session.getId());
    cookie.setMaxAge(20);
    response.addCookie(cookie);
%>

Session 的声明周期

问题:是否浏览器访问服务端的任何一个JSP或者Servlet,服务端都会立即创建一个HttpSession对象呢?

不一定,

1、若当前的JSP或者Servlet是客户端访问当前WEB应用的第一个资源,且JSP的page指定的session属性值为false,则服务器就不会为JSP创建一个HttpSession对象

2、若当期JSP不是客户端访问的当前WEB应用的第一个资源,且其他页面已经创建了一个HttpSession对象,则当前JSP页面会返回一个会话的HttpSession对象,而不会创建一个新的HttpSession对象.

session="false" 意思为JSP页面禁用session隐含变量,但是可以显式的创建HttpSession对象.

session的创建

1). 默认情况下, 第一次访问一个 WEB 应用的一个 JSP 页面时, 该页面都必须有一个和这个请求相关联的 Session 对象. 
因为 page 指定的 session 属性默认为 true

2). 若把 session 属性改为 false, JSP 页面不会要求一定有一个 Session 对象和当前的 JSP 页面相关联
所以若第一次访问当前 WEB 应用的 JSP 页面时, 就不会创建一个 Session 对象. 

3). 创建一个 Session 对象: 若 page 指定的 session 设置为 false 或 在 Servlet 中可以通过以下 API 获取 Session 对象. 

request.getSession(flag): 若 flag 为 true, 则一定会返回一个 HttpSession 对象, 如果已经有和当前 JSP 页面关联的 HttpSession
对象, 直接返回; 如果没有, 则创建一个新的返回. flag 为 false: 若有关联的, 则返回; 若没有, 则返回 null

session的销毁

①. 直接调用 HttpSession 的 invalidate()
②. HttpSession 超过过期时间. 

> 返回最大时效: getMaxInactiveInterval() 单位是秒
> 设置最大时效: setMaxInactiveInterval(int interval)
> 可以在 web.xml 文件中配置 Session 的最大时效, 单位是分钟. 
也可以在tomcat配置文件中conf/web.xml设置
        30    

③. 卸载当前 WEB 应用. 
注意: 关闭浏览器不会销毁 Session!

<% 
    HttpSession session = request.getSession(true);
    out.println(session);
    out.print("<br>");

    //设置seesion有效期5s钟
    session.setMaxInactiveInterval(5);
    //获取 Session 的最大时效, 默认为 30 分钟. 
    out.print(session.getMaxInactiveInterval());
    session.invalidate();
%>

Session常用方法

登录案例:用户登录案例.

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

    SessionID: <%= session.getId() %>
    <br><br>

    IsNew: <%= session.isNew() %>
    <br><br>

    MaxInactiveInterval: <%= session.getMaxInactiveInterval() %>
    <br><br>

    CreateTime: <%= session.getCreationTime() %>
    <br><br>

    LastAccessTime: <%= session.getLastAccessedTime() %>
    <br><br>

    <% 
        Object username = session.getAttribute("username");
        if(username == null){
            username = "";
        }
    %>

    <form action="hello.jsp" method="post">
        username: <input type="text" name="username" 
            value="<%= username %>"/>
        <input type="submit" value="Submit"/>
    </form>

</body>
</html>

hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

    SessionID: <%= session.getId() %>
    <br><br>

    IsNew: <%= session.isNew() %>
    <br><br>

    MaxInactiveInterval: <%= session.getMaxInactiveInterval() %>
    <br><br>

    CreateTime: <%= session.getCreationTime() %>
    <br><br>

    LastAccessTime: <%= session.getLastAccessedTime() %>
    <br><br>

    Hello: <%= request.getParameter("username") %>
    <br><br>

    <% 
        session.setAttribute("username", request.getParameter("username")); 
    %>

    <a href="login.jsp">重新登录</a>    
    &nbsp;&nbsp;&nbsp;&nbsp;
    <a href="logout.jsp">注销</a> 

</body>
</html>

logout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

    SessionID: <%= session.getId() %>
    <br><br>

    IsNew: <%= session.isNew() %>
    <br><br>

    MaxInactiveInterval: <%= session.getMaxInactiveInterval() %>
    <br><br>

    CreateTime: <%= session.getCreationTime() %>
    <br><br>

    LastAccessTime: <%= session.getLastAccessedTime() %>
    <br><br>

    Bye: <%= session.getAttribute("username") %>
    <br><br>

    <a href="login.jsp">重新登录</a>    

    <% 
        //使session失效
        session.invalidate();
    %>

</body>
</html>

利用URL重写实现Session跟踪

如果把cookie禁用后,如何跟踪session呢.?

  • Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。这种补充机制要求在响应消息的实体内容中必须包含下一次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。 
  • 将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URL重写。如果在浏览器不支持Cookie或者关闭了Cookie功能的情况下,WEB服务器还要能够与浏览器实现有状态的会话,就必须对所有可能被客户端访问的请求路径(包括超链接、form表单的action属性设置和重定向的URL)进行URL重写。

HttpServletResponse接口中定义了两个用于完成URL重写方法: