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