真的了解Session吗 - Session详解

前言

前面了解了HTTP的无状态性
为了解决无状态的问题,有两种技术:Cookie和Session
学习了Cookie,现在来了解Session


目录

  1. Session简介
  2. Session API
  3. Session的使用
    3.1. 存取数据
    3.2. 生命周期
    3.3. 钝化活化
  4. Session与Cookie
    4.1. URL地址重写
    4.2. Session与Cookie的区别
    4.3. 联合使用
  5. 总结

Session简介

无状态是指:服务器不会保存客户端-服务器会话的临时数据,每一次会话都是独立的

这会造成每次购物操作都需要重新登录,解决办法有两个:Cookie与Session
Cookie存储在客户端,Session存储在服务器

Cookie技术:
真的了解Session吗 - Session详解_第1张图片

可以看到,当服务器给客户端创建了Cookie后,如果想要保持上下文的相关信息,就都需要在Request中带上Cookie

这就造成了一个很大的局限:Cookie如果很多,就会增加客户端与服务器的传输数据,而且由于浏览器会对Cookie做一定的限制,就不能保持太多的信息

为了解决这个局限,建立在Cookie上的Session就出现了

Session的作用就是在服务端保持数据,然后传递给客户端一个叫JSESSIONID 的Cookie,客户端仅需带着这个JSESSIONID 就可以获得保持的数据

真的了解Session吗 - Session详解_第2张图片


Session API

在JavaWeb中,使用Session调用的是HttpSession接口的方法

真的了解Session吗 - Session详解_第3张图片

既然是接口及抽象方法,那么具体是谁实现的呢?

HttpSession的具体实现是由服务器来完成的
比如tomcat,在tomcat的src中java\org\apache\catalina\session下的类StandardSession实现了HttpSession
(这个关系到Tomcat源码,就不往下深究了)

这些API各有什么作用?

API 作用
Object getAttribute(String); 获取Session属性
Enumeration getAttributeNames(); 获取Session所有的属性名
long getCreationTime() 获取Session被创建时间
String getId() 获取Session的id
long getLastAccessedTime() 返回Session最后活跃的时间
ServletContext getServletContext(); 获取ServletContext对象
void setMaxInactiveInterval(int var1); 设置Session超时时间
int getMaxInactiveInterval() 获取Session超时时间
void setAttribute(String var1, Object var2); 设置Session属性
void removeAttribute(String var1); 移除Session属性
void invalidate(); 销毁该Session
boolean isNew(); 判断该Session是否为新的

Session的使用

Session是一个域对象,类似与Servletcontext,可以用来保存数据、保存会话临时数据

存取数据

编写一个存入数据的Servlet:

package Session;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class SessionTest extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //得到Session
        HttpSession httpSession =  req.getSession();
        //存入数据
        httpSession.setAttribute("name","zhangsan");
    }
}

编写一个得到数据的Servlet:

package Session;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

public class SessionTest1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        String name = (String) session.getAttribute("name");
        PrintWriter writer = resp.getWriter();
        writer.write(name);
    }
}

在web.xml中关联这两个Servlet

访问:http://localhost:8080/sessionTest
真的了解Session吗 - Session详解_第4张图片

服务器给了客户端一个JSESSIONID
访问:http://localhost:8080/sessionTest1

客户端带着这个JSESSIONID可以得到name值
真的了解Session吗 - Session详解_第5张图片

生命周期

  1. Session在用户第一次访问服务器jsp动态资源会被自动创建(Jsp本质上是一个Servlet,源码中调用了request.getSession()方法)或者servlet中调用request.getSession()时创建,Session对象保存在内存里
  2. 既然动态资源会创建,静态资源会吗?当然是不会,打开一个HTML并不会调用到Servlet

还记得前面这个图,Web服务器直接调用静态页面,并不会经过Servlet容器
真的了解Session吗 - Session详解_第6张图片

  1. 活跃时间,前面有一个API是getLastAccessedTime,获得Session最后一次活跃时间,也就是说服务器会更新客户端访问Session的时间

  2. 超时时间,随着客户的创建,Session会越来越多,通过超时时间来约束Session,Session的默认超时时间是30分钟

这是Tomcat的设计,可以在web.xml中找到
真的了解Session吗 - Session详解_第7张图片

修改方式:
(1)在Tomcat下的web.xml中修改,会使所有使用该Tomcat的Web工程都改变(这个web.xml类似于所有工程配置的父类)
(2)在自己的工程的web.xml中设置,仅会影响自己的工程
真的了解Session吗 - Session详解_第8张图片

(3)通过API设置:setMaxInactiveInterval(int var1),这里的单位是秒

  1. 可以使 Session 对象释放的情况:
    Session对象空闲时间超时,自动释放
    手动释放Session (invalidate方法)
    对象被强制失效
    Web 应用卸载
    服务器进程停止

注意:Session和Cookie所说的超时是不一样的,Session的超时时间是指空闲时间,多久没有访问该Session;而Cookie是超时时间是当Cookie创建时开始计算,不管有没有访问Cookie

钝化活化

钝化:当服务器正常关闭,还存活着的Session,会序列化到磁盘上,而不再占用内存空间,以文件(“SESSIONS.ser”)的形式存储在tomcat的work目录下(IDEA打开的存放在IDEA设置的本地地址)
真的了解Session吗 - Session详解_第9张图片

虽然记事本打开乱码了,但是大致看的出确实是我们的Session

真的了解Session吗 - Session详解_第10张图片
活化:Session 被钝化后,服务器再次调用Session对象时,将 Session对象由磁盘中加载到内存中使用

注意:

  1. 如果Session中数据想要随着Session一起钝化,需要实现序列化接口Serializable
  2. 钝化后,Session不会超过Session超时时间而过期,这个文件会保存到下次启动服务器时消失

启动后:

真的了解Session吗 - Session详解_第11张图片

  1. 多个Session钝化会保存在一个文件中

如果想要设置钝化
(1)在tomcat里面 conf/context.xml 里面配置,对所有的运行在这个服务器的项目生效
(2)在conf/Catalina/localhost/context.xml 配置 ,对 localhost生效
(3)在自己的web工程项目中的 META-INF/context.xml,只对当前的工程生效

一个Context就是一个工程
配置:

<Context>
    <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
        <Store className="org.apache.catalina.session.FileStore" directory="D:"/>
    </Manager>
</Context>

maxIdleSwap代表空闲时间,一分钟没使用Session就钝化
directory表示钝化文件存储位置


Session与Cookie

使用Session时,服务器会自动创建一个Cookie,并设置Cookie属性为:

JSESSIONID=E7B846EA2368DAD4BDF71E1274AA42F2

可以看出Session是基于Cookie实现的,Session的真实数据存储在服务器,客户端凭借JSESSIONID可以使用该Session数据

该Cookie是服务器自己创建的,所有的属性都是默认值,maxAge值默认是-1,该Cookie仅当前浏览器使用,不可被持久化

如果浏览器禁用了Cookie,怎么使用Session?

URL地址重写

在浏览器中禁用Cookie
真的了解Session吗 - Session详解_第12张图片

禁用了之后,就没有JSESSIONID的cookie了
真的了解Session吗 - Session详解_第13张图片

访问sessionTest1当然会报错
真的了解Session吗 - Session详解_第14张图片

HttpServletResponse类提供了两个URL地址重写的方法:

  • encodeURL(String url)

  • encodeRedirectURL(String url)

随便使用一个:在SessionTest中加上URL重写

String url = "/sessionTest1";
resp.sendRedirect(resp.encodeURL(url));

输入地址:http://localhost:8080/sessionTest

自动跳到sessionTest1,且在URL中带上参数JSESSIONID

在这里插入图片描述

浏览器确实没有Cookie
真的了解Session吗 - Session详解_第15张图片

URL重写方法会自动判断该浏览器是否支持Cookie,如果不支持Cookie,重写后的URL地址会带上jsessionid

Session与Cookie的区别

  1. 存储位置、隐私安全
    Session是存储在服务器上,对客户是透明的,安全性较高(也高不到哪去,毕竟也是通过Cookie实现)
    Cookie是存储在客户端上,客户可见,即安全性低
  2. 存储方式
    Session可以存储任何数据键值对(类似与Map)
    Cookie只能存储字符串,而且因为版本属性原因,对存储的字符串有诸多要求
  3. 有效期
    Session的超时设置是空闲时间,而且浏览器关闭Session就会失效
    Cookie的超时设置是从创建开始计算,而且可以持久化
  4. 资源消耗
    Session是保存在服务器的,每个用户都会产生一个Session,如果是并发访问的用户非常多,是不能使用Session的,Session会消耗大量的内存。
    Cookie是保存在客户端的。不占用服务器的资源。像baidu、Sina这样的大型网站,一般都是使用Cookie来进行会话跟踪
  5. 浏览器支持
    浏览器禁用Cookie,Session可以通过URL重写实现
    而Cookie无效
  6. 跨域名
    Session是基于一个默认属性的Cookie,即无法跨域名,仅在当前域名使用
    Cookie可以设置domain属性跨域名
  7. 限制访问
    Session基于一个默认属性的Cookie,path设置为/,所有当前浏览器都可以访问
    Cookie可以设置path属性,限制Servlet访问

联合使用

既然Session受限与Cookie的默认属性,那么我们自定义一个Cookie,在将Session存储进Cookie中不就可以了?

Cookie cookie = new Cookie("JSESSIONID",session.getId());

当然,也可以暴力点,直接把Tomcat中的Session设置改了
修改Tomcat的配置文件server.xml
一个contenxt就是一个会话
在< Host>节点下增加< Context>节点,并设置path,docBase,debug和reloadable属性和一些session配置

<Context path="" docBase="webapp" debug="0" reloadable="false" sessionCookiePath="/" sessionCookieName=""/>

Tomcat配置
一般我们将WEB应用打包成WAR格式,然后拷贝到TOMCAT的WEBAPP目录下进行发布
在正常情况下,TOMCAT将自动解压WAR文件并生成对应的目录,而且会在内存中动态创建该WEB应用对应的CONTEXT路径。比如我们的WAR文件是JavaWeb.war,那么解压后的目录就是JavaWeb目录,在内存中动态创建的Context路径就是/JavaWeb。
在开发阶段这样的默认行为是可以接受的,但是在正式部署的情况下,我们通常需要修改应用的Context路径以适应我们的需要

如果我们想让用户仅仅输入域名来访问我们的JavaWeb应用,我们就需要修改Tomcat的Context设置
可以在conf/server.xml下增加一个context结点

<Context path="/javaweb" docBase="D:/JavaProject/JavaWeb" debug="0" reloadable="true">  
          <WatchedResource>WEB-INF/web.xml</WatchedResource>     
</Context>

总结

  1. HttpSession是抽象类,通过服务器实现Session(这就是为什么可以通过Request得到Session)
  2. Session有很多API,了解了一下
  3. Session是一个域对象,可以存取任何类型的数据
  4. Session是基于一个默认的Cookie实现,Cookie属性为:JSESSIONID=value,浏览器仅需带着这个Cookie就可得到服务器端的Session数据
  5. 因为Session是基于一个默认的Cookie,受限于默认Cookie的属性
  6. 可以联合Session和Cookie,实现需求

你可能感兴趣的:(JavaWeb,java,session,servlet,cookie,web)