JavaWeb的session及其共享技术

1.什么叫会话

​ 一次会话指的是:就好比打电话,A给B打电话,接通之后,会话开始,直到挂断电话,该次会话就结束了,而浏览器访问服务器,就跟打电话一样,浏览器A给服务器发送请求,访问web程序,该次会话就已经接通,其中不管浏览器发送多少请求(就相当于接通电话后说话一样),都视为一次会话,直到浏览器关闭,本次会话结束。

​ 其中注意,一个浏览器就相当于一部电话,如果使用火狐浏览器,访问服务器,就是一次会话了,然后打开google浏览器,访问服务器,这是另一个会话,虽然是在同一台电脑,同一个用户在访问,但是,这是两次不同的会话。

2.引入cookie和session

​ 思考一个问题,一个浏览器访问一个服务器就能建立一个会话,如果别的电脑,都同时访问该服务器,就会创建很多会话,就拿一些购物网站来说,我们访问一个购物网站的服务器,会话就被创建了,然后就点击浏览商品,对感兴趣的商品就先加入购物车,等待一起付账,这看起来是很普通的操作,但是想一下,如果有很多别的电脑上的浏览器同时也在访问该购物网站的服务器,跟我们做类似的操作呢?服务器又是怎么记住用户,怎么知道用户A购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,不能放入用户B或用户C的购物车内的呢?

​ 这里我们就用cookie和session两种会话跟踪技术来跟踪整个会话。

3.cookie简介

3.1.cookie的工作原理

JavaWeb的session及其共享技术
1)首先浏览器向服务器发出请求。

2)服务器就会根据需要生成一个Cookie对象,并且把数据保存在该对象内。

3)然后把该Cookie对象放在响应头,一并发送回浏览器。

4)浏览器接收服务器响应后,提出该Cookie保存在浏览器端。

5)当下一次浏览器再次访问那个服务器,就会把这个Cookie放在请求头内一并发给服务器。

6) 服务器从请求头提取出该Cookie,判别里面的数据,然后作出相应的动作。

3.2.cookie中的常用方法

Cookie cookie=new Cookie(String name,String value) 构造一个cookie对象

response.addCookie(Cookie cookie) 是将一个cookie对象传入客户端。

request.getCookies() 得到所有的cookie对象

cookie.getName() 得到此cookie对象的名字

cookie.getValue() 得到对应名称的cookie的值

cookie.setMaxAge() 设置过期时间

3.3.案例

@WebServlet("/CookieServletDemo1")
public class CookieServletDemo1 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public CookieServletDemo1() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // 创建cookie对象
    // cookie中`存放的数据以键值对存在map<String,String> 键和值都只能是字符串,不支持中文
    Cookie cookie = new Cookie("username", "zhangsan");
    Cookie cookie1 = new Cookie("password", "1234");
    // 失效时间 以秒为单位
    cookie.setMaxAge(60 * 60);
    response.addCookie(cookie);
    response.addCookie(cookie1);
  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}
@WebServlet("/CookieServletDemo2")
public class CookieServletDemo2 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public CookieServletDemo2() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    //      从请求头中获取cookie信息
    Cookie[] cookies = request.getCookies();
    for(Cookie c:cookies){
      System.out.println(c.getName()+"===="+c.getValue());
    }
  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}

3.4.浏览器中查看cookie

不同的浏览器略有差别,这里以谷歌浏览器为例。

F12打开开发者工具 ---点击Application选项---选中其中的cookie---选择相应的站点---看到该站点中的所有cookie信息。

3.5.cookie的应用场景

​ cookie的应用场景有很多,最具代表性的当属网站的记录用户账号和密码的功能了,大家可能经常看到登录某某论坛,某某网站时,下面有个选项为N天内自动登录,其实这就是cookie的应用。当用户第一次输入账号密码时给服务器发送请求时,服务器会根据账号密码回写一个字符串cookie,当用户下次再向该服务器发送登录请求时,则带着这个字符串cookie一起去访问服务器,这时,服务器只需要对比次字符串和数据库中存储的字符串是否相同,则可以达到用户自动登录功能。

3.6.cookie的局限性

  • Cookie数量和长度的限制。每个站点最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。
  • cookie中只能存字符串。且不支持中文
  • cookie不适合保存敏感数据(例如密码)可见的

4.session

4.1.session的工作原理

JavaWeb的session及其共享技术

1)浏览器发出请求到服务器。

2)服务器会根据需求生成Session对象,并且给这个Session对象一个编号,一个编号对应一个Session对象

3)服务器把需要记录的数据封装到这个Session对象里,然后把这个Session对象保存下来。

4)服务器把这个Session对象的编号放到一个Cookie里,随着响应发送给浏览器

5)浏览器接收到这个cookie就会保存下来

6)当下一次浏览器再次请求该服务器服务,就会发送该Cookie

7)服务器得到这个Cookie,取出它的内容,它的内容就是一个Session的编号!!!

8)凭借这个Session编号找到对应的Session对象,然后利用该Session对象把保存的数据取出来!

4.2.session的常用方法

方法 解释
void setAttribute(String attribute, Object value) 设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大
String getAttribute(String attribute) 返回Session属性
void removeAttribute(String attribute) 移除Session属性
String getId() 返回Session的ID。该ID由服务器自动创建,不会重复
long getCreationTime() 返回Session的创建日期。
long getLastAccessedTime() 返回Session的最后活跃时间。返回类型为long
int getMaxInactiveInterval() 返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效
void setMaxInactiveInterval(int second) 设置Session的超时时间。单位为秒4.3.

4.3.案例

@WebServlet("/SeesionServletDemo1")
public class SeesionServletDemo1 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public SeesionServletDemo1() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    // 创建session对象
    HttpSession session = request.getSession();
    System.out.println(session.getId());

    session.setAttribute("name", "zhangsan");

    session.setAttribute("student", new Student(1, "zhangsan", 12));
    Student stu = (Student) session.getAttribute("student");

    stu.setName("lisi");

    // 设置过期时间 单位是秒
    //      session.setMaxInactiveInterval(2);
    // 直接销毁session  注销登录
    //      session.invalidate();

  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}
public class Student {

  private Integer id;
  private String name;
  private Integer age;
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  public Student(Integer id, String name, Integer age) {
    super();
    this.id = id;
    this.name = name;
    this.age = age;
  }
  public Student() {
    super();
    // TODO Auto-generated constructor stub
  }
}
@WebServlet("/SeesionServletDemo2")
public class SeesionServletDemo2 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public SeesionServletDemo2() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    // 创建session对象
    HttpSession session = request.getSession();

    System.out.println(session.getAttribute("name"));

    Student stu = (Student) session.getAttribute("student");
    System.out.println(stu.getName());

  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}

4.4.session的生命周期

session对象生命周期:

  • session对象什么创建?
    • 执行request.getSession()方法时
  • session对象什么销毁?
    • 默认情况下,session对象在30分钟之后服务器自动销毁。
    • 手动设置session有效时长
    • void setMaxInactiveInterval(int interval) -以秒为单位。
    • 手动销毁
    • void invalidate()

4.5.session在一次会话结束后消失的原因

​ 由于session的使用需要依赖cookie,cookie每次从浏览器端传输session的id到后台,然后查找对应编号的session进行使用,但由于此时的cookie默认的失效时间是一次会话,当一次会话结束后,存放id的cookie对象就消失了,下一次会话访问时就会生成新的id,那存储在原来的session对象中的数据就无法找到了。

4.6.浏览器禁用cookie能否使用session

可以,但需要手动拼接id传过去,例如

http://localhost:8080/day06/session.jsp;jsessionid=AE62ECBAAD2CA16DA6AEBF1D1527CD45

jsessionid指的就是session对应的id

4.7.session共享

4.7.1.基于数据库的Session共享

首选当然是大名鼎鼎的Mysql数据库,并且建议使用内存表Heap,提高session操作的读写效率。这个方案的实用性比较强,相信大家普遍在使用,它的缺点在于session的并发读写能力取决于Mysql数据库的性能,同时需要自己实现session淘汰逻辑,以便定时从数据表中更新、删除 session记录,当并发过高时容易出现表锁,虽然我们可以选择行级锁的表引擎,但不得不否认使用数据库存储Session还是有些杀鸡用牛刀的架势。

4.7.2.基于Cookie的Session共享

​ 这个方案我们可能比较陌生,但它在大型网站中还是比较普遍被使用。原理是将全站用户的Session信息加密、序列化后以Cookie的方式, 统一种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有Cookie内容的特性,从而实现 用户的Cookie化Session 在多服务间的共享访问。

  这个方案的优点无需额外的服务器资源;缺点是由于受http协议头信心长度的限制,仅能够存储小部分的用户信息,同时Cookie化的 Session内容需要进行安全加解密(如:采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带宽资源,因为浏览器会在请求当前域名下任何资源时将本地Cookie附加在http头中传递到服务器。

4.7.3.基于Memcache的Session共享

 Memcache由于是一款基于Libevent多路异步I/O技术的内存共享系统,简单的Key + Value数据存储模式使得代码逻辑小巧高效,因此在并发处理能力上占据了绝对优势,目前本人所经历的项目达到2000/秒 平均查询,并且服务器CPU消耗依然不到10%。

  另外值得一提的是Memcache的内存hash表所特有的Expires数据过期淘汰机制,正好和Session的过期机制不谋而合,降低了 过期Session数据删除的代码复杂度,对比“基于数据库的存储方案”,仅这块逻辑就给数据表产生巨大的查询压力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章