Java Web 学习与总结(三)会话跟踪

  何为会话跟踪?举个简单的例子,比如登陆到某购物网站后,在一定时间内无论你在这个网站中切换到任意的网页,只要不执行退出操作,一直保持着你账号的登录状态。

  那么在Java Web中我们应当如何去实现这一操作呢?这里给大家介绍三种技术:cookie、session和URL重写技术。

  首先是cookie技术,cookie在平时我们的使用时经常可以在安全设置中看到,它其实是服务器段在客户端本地保存的一些数据,同之前我们学到的Arribute一样,也是由key-value结构组成的。它是一种在客户端保持绘画跟踪的解决方案。在用户第一次访问服务器时,由服务器通过响应头的方式发送给客户端浏览器;当用户再次向服务器发送请求时会附带上这些文本信息。通过cookie,服务器在手收到来自客户端浏览器的请求时,能够通过分析请求头的内容而得到客户端特有的信息,从而动态的生成与该客户端相对应的内容,比如在很多网站登录时我们会看到类似“记住我”的选项,其实选中了就是把你的登陆信息保存在本地了,下次访问网站时自然而然的就附带了上次的登陆信息,从而达到免再次登陆的功能。

  cookie在javax.servlet.http内的源码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package javax.servlet.http;

import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;

public class Cookie implements Cloneable, Serializable {
    private static final CookieNameValidator validation;
    private static final long serialVersionUID = 1L;
    private final String name;
    private String value;
    private int version = 0;
    private String comment;
    private String domain;
    private int maxAge = -1;
    private String path;
    private boolean secure;
    private boolean httpOnly;

    public Cookie(String name, String value) {
        validation.validate(name);
        this.name = name;
        this.value = value;
    }

    public void setComment(String purpose) {
        this.comment = purpose;
    }

    public String getComment() {
        return this.comment;
    }

    public void setDomain(String pattern) {
        this.domain = pattern.toLowerCase(Locale.ENGLISH);
    }

    public String getDomain() {
        return this.domain;
    }

    public void setMaxAge(int expiry) {
        this.maxAge = expiry;
    }

    public int getMaxAge() {
        return this.maxAge;
    }

    public void setPath(String uri) {
        this.path = uri;
    }

    public String getPath() {
        return this.path;
    }

    public void setSecure(boolean flag) {
        this.secure = flag;
    }

    public boolean getSecure() {
        return this.secure;
    }

    public String getName() {
        return this.name;
    }

    public void setValue(String newValue) {
        this.value = newValue;
    }

    public String getValue() {
        return this.value;
    }

    public int getVersion() {
        return this.version;
    }

    public void setVersion(int v) {
        this.version = v;
    }

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException var2) {
            throw new RuntimeException(var2);
        }
    }

    public void setHttpOnly(boolean httpOnly) {
        this.httpOnly = httpOnly;
    }

    public boolean isHttpOnly() {
        return this.httpOnly;
    }

    static {
        boolean strictServletCompliance;
        String propStrictNaming;
        String propFwdSlashIsSeparator;
        if (System.getSecurityManager() == null) {
            strictServletCompliance = Boolean.getBoolean("org.apache.catalina.STRICT_SERVLET_COMPLIANCE");
            propStrictNaming = System.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING");
            propFwdSlashIsSeparator = System.getProperty("org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
        } else {
            strictServletCompliance = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                public Boolean run() {
                    return Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE"));
                }
            });
            propStrictNaming = (String)AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    return System.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING");
                }
            });
            propFwdSlashIsSeparator = (String)AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    return System.getProperty("org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
                }
            });
        }

        boolean strictNaming;
        if (propStrictNaming == null) {
            strictNaming = strictServletCompliance;
        } else {
            strictNaming = Boolean.parseBoolean(propStrictNaming);
        }

        boolean allowSlash;
        if (propFwdSlashIsSeparator == null) {
            allowSlash = !strictServletCompliance;
        } else {
            allowSlash = !Boolean.parseBoolean(propFwdSlashIsSeparator);
        }

        if (strictNaming) {
            validation = new RFC2109Validator(allowSlash);
        } else {
            validation = new RFC6265Validator();
        }

    }
}

从源码中我们可以看到cookie对象的构造函数是public Cookie(String name, String value),那么我们在Servlet中创建cookie也是根据这种构造方法来创建(这里命名为unameCookie):

  Cookie unameCookie = new Cookie("key","value");

创建对象后,我们服务器向客户端响应Cookie时需要这一函数:

  response.addCookie(unameCookie);

通过这两步后,我们便将名字为key,值为value的Cookie对象保存在了用户的客户机上,当我们要使用cookie内保存的数据时时需要通过以下方法获取并遍历:

  Cookie[] cookies = request.getCookie();

  String value = null;

  if(cookies != null){

    for(Cookie c: cookies){

      if(c.getName() .equal("key")){

        value = c.getValue();

      }

    }

  }

这里通过request.getCookie()得到响应头中的cookie内容,然后通过遍历cookie数组比较通过getName()得到的名字,再获取我们需要的值。

但是我们要注意,在默认情况下cookie只能被创建它的应用获取。Cookie的setPath()方法可以重新指定其访问路径,例如将其设置为在某个应用下的某个路径共享,或者在同一服务器内的所有应用共享:

  unameCookie.setPath("/chapter/jsp/");

这样就让unameCookie能在/chapter/jsp/目录下所有的应用共享,当然我们也可以通过以下方式让服务器下的所有应用共享:

  unameCookie.setPath("/");

Cookie有一定的存活时间,不会在客户端一直保存。默认情况下,Cookie保存在浏览器内存中,在浏览器关闭时失效,这种Cookie也成为临时Cookie,若要其长时间保存,我们需要通过setMaxAge()方法设置其存活时间(以秒为单位),时间若为正整数,表示其存活的秒数,若为负数,表示为临时Cookie,若为0,则通知浏览器删除相应的Cookie。

  unameCookie.setMaxAge(60*60);//保存一个小时的cookie

要注意,保存的Cookie仅限在同一个浏览器下且允许Cookie下访问来使用,cookie可能被禁用,可能被其他软件删除,它的大小和个数受限,单个不能超过4kb,很多浏览器都只允许一个站点最多保持20个Cookie,另外,它的安全性也不够高,是以纯文本的形势记录在文件中,最好在保存前加密处理一下。

 

 

  再一个就是最常用的Session技术,这是一种在服务器端保持会话跟踪的解决方案,使用了HttpSession对象,这个对象是javax.servlet.http.HttpSession接口的实例,也称为会话对象,该对象用来保存单个用户访问时的一些信息,是服务器在无状态的HTTP协议下用来识别和维护具体某个用户的主要方式。

  HttpSession对象会在用户第一次访问服务器时由容器创建(注意只是在访问JSP、Servlet等程序在会创建,访问静态资源并不会创建),当用户调用其失效方法(invalidate()方法)或超过其最大不活动时间时会失效。在此期间,来自同一客户端的用户与服务器之间的多次请求都属于同一会话。

  服务器在创建会话对象时,会为其分配一个唯一的会话标识:SessionId,以JSESSIONID的属性名保存在客户端Cookie中,在用户随后的请求中,服务器通过该Cookie中的JSESSIONID属性值来识别不同的用户。

  从这里我们看出,实际上通过读取存取临时Cookie我们就可以达到保持用户连接的功能,Session技术实际就是把这一功能规范化,但是数据是存储在服务器上,当访问量增多时会造成服务器性能负担加重,下面我们来看如何使用这一技术。

HttpSession源码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package javax.servlet.http;

import java.util.Enumeration;
import javax.servlet.ServletContext;

public interface HttpSession {
    long getCreationTime();

    String getId();

    long getLastAccessedTime();

    ServletContext getServletContext();

    void setMaxInactiveInterval(int var1);

    int getMaxInactiveInterval();

    /** @deprecated */
    @Deprecated
    HttpSessionContext getSessionContext();

    Object getAttribute(String var1);

    /** @deprecated */
    @Deprecated
    Object getValue(String var1);

    Enumeration<String> getAttributeNames();

    /** @deprecated */
    @Deprecated
    String[] getValueNames();

    void setAttribute(String var1, Object var2);

    /** @deprecated */
    @Deprecated
    void putValue(String var1, Object var2);

    void removeAttribute(String var1);

    /** @deprecated */
    @Deprecated
    void removeValue(String var1);

    void invalidate();

    boolean isNew();
}

Session的使用方法如下:

  获取HttpSession对象:HttpSession session = request.getSession();

  存取会话值属性:

  存储:session.setAttribute("key","name");

  取出:String uanme = (String)session.getAttribute("key");

  移除:session.removeAttribute("key");

  这里实际上和存取Cookie差不多,这一会话在网站服务器路径下的应用中都保持一致,存储的value对象也不仅仅是String,是任意的对象(泛型),需要什么就存什么,只需要在取出是转化为当时存储的类型就好了,

  获取会话的最大不活动时间:

  int time = session.getMaxInactiveInterval();//单位为秒

  设置会话的最大不活动时间:

  session.setMaxInactiveInterval(600);

  设置会话立刻失效:

  session.invalidate();

  服务器在执行会话失效代码后,会立刻清除会话对象及其所有会话域属性,同时响应客户端浏览器清除Cookie中的JSESSIONID。在实际应用中此方法多用来实现系统的“安全退出”,使客户端和服务器彻底结束此次回话,清除所有会话相关信息,防止会话劫持等黑客攻击,

  此外,在多数情况下,Session需要借助Cookie才能正常工作,如果客户端完全禁止Cookie,Session将失效。

 

 

  URL重写技术主要是在不能确定客户端浏览器是否支持Cookie的情况下,使用URL重写技术可以对请求的URL地址追加会话标识,从而实现用户的会话跟踪功能。URL重写是指服务器程序对接收的URL请求重新写成网站可以处理的另一个URL过程,URL重写技术是实现动态网站会话跟踪的的重要保障。

  例如对于一个请求地址:http://localhost:8080/chapter/Servlet1

  经过重写后,地址格式变为:http://localhost:8080/chapter/Servlet1;jsessionid=5678978e7r9w7r8we7r8w7e89r7we9

  其中的jsessionid是不是在上一段中是不是很熟悉!!!这就是通过url追加的会话标识,服务器即通过它来识别跟踪某个用户的访问。

  URL重写的示例代码如下所示:

  1.encodeURL方法:out.Print("<a href=' " + response.encodeURL("Servlet1" + " ')'>链接请求</a>")

  2.encodeRedirectURL方法:response.sendRedirect(response.encodeRedirectURL("Servlet1"));

  在使用时,我们通常用一个String对象来获取encodeURL方法得到的链接来进行请求,用encodeRedirectURL方法来进行重定向来进行Session的保持。

  

  还用一种是通过form表单隐藏域来进行,但这种方法只能通过表单来传递标志信息,意义不大,这里不再叙述。

 

转载于:https://www.cnblogs.com/qq965921539/p/10169656.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值