前面已经说过关于Cookie和HttpSession,这两种保存会话数据的两种技术,今天在这里细说一下。
Cookie —只能存字符串,不能存对象
Cookie是客户端的技术,程序把每个用户的数据以Cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去,这样,web资源处理的就是用户自己的数据了。
HttpSession ----可存储对象。
HttpSession是服务端的技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个独享的HttpSession对象,由于Session为用户自己浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据资源放在各自的session中,当用户再去访问服务器中的其他web资源时,其他web资源再从用户各自的Session中取出数据为用户服务。
Cookie和Session的区别:
Cookie : 是吧用户的数据写给用户的浏览器
Session : 是把用户的数据写到用户独占的session中。session对象是由服务器创建,可以由reqest.getSession方法得到session。
关联:sessionID本身放到session中去,同时也会复制一份给JSsessionID,因此这个两者是一样的(其实我们去验证就是将两者匹配)
Cookie API----浏览器应该支持每台web服务器又20个cookie,总共300个cookie,并且每一个cookie 的大小限定为4KB。
Cookie是客户端的技术,是因为Cookie数据是由客服端来保存和携带的,所以被称为客户端的技术。
所在位置:javax.servlet.http.Cookie,该类的是这么定义的:public class Cookie implements Cloneable, Serializable,里面定义了很多的方法 , 源码如下:(Cookie属性)
public class Cookie implements Cloneable, Serializable {
private static final CookieNameValidator validation;
private static final long serialVersionUID = 1L;
private final String name;
private String value;
static {
String prop = System
.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING");
boolean strictNaming;
boolean strictNaming;
if (prop != null) {
strictNaming = Boolean.parseBoolean(prop);
} else {
strictNaming = Boolean
.getBoolean("org.apache.catalina.STRICT_SERVLET_COMPLIANCE");
}
if (strictNaming) {
validation = new RFC2109Validator();
} else {
validation = new NetscapeValidator();
}
}
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) { // 设置Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明。
this.comment = purpose;
}
public String getComment() { //取得Cookie的用处说明,览器显示Cookie信息的时候显示该说明。
return this.comment;
}
public void setDomain(String pattern) { // 设置该Cookie的域名
this.domain = pattern.toLowerCase(Locale.ENGLISH);
}
public String getDomain() { // 可以访问该Cookie的域名。如果设置为”.google.com”,则所有以”google.com”结尾的域名都可以访问该Cookie。
注意第一个字符必须为“.”
return this.domain;
}
/**
*MaxAge,负数:cookie的数据存在浏览器缓存中。0 :删除,删除时路径要不保持一致,否则删错。正数:缓存的时间。
*这里需要注意一点:设置为0删除,设置该项之前,必须确定删除cookie的路径。
*/
public void setMaxAge(int expiry) { // 正值表示cookie将在经过该值数秒后过期。注意,该值是cookie过期的最大生存时间,不是cookie当前时间。
this.maxAge = expiry; // 负值意味着cookie将不会被持久存储,将在web浏览器退出时,删除。0值将会导致删除cookie.
}
public int getMaxAge() { // cookie以秒为单位的指定Cookie的最大生存时间 ,默认为 -1指示该cookie将保存到浏览器关闭为止。
return this.maxAge;
}
public void setPath(String uri) { // 设置cookie的路径
this.path = uri;
}
public String getPath() { // 获取cookie路径
return this.path;
}
public void setSecure(boolean flag) { // 该Cookie是设置否仅被使用安全协议传输。安全协议有HTTPS,SSL等。但是不具有加密,如果想要加密自己写
this.secure = flag;
}
public boolean getSecure() { // 取得
return this.secure;
}
public String getName() { // 取得该Cookie的名称
return this.name;
}
public void setValue(String newValue) { //设置该Cookie的值
this.value = newValue;
}
public String getValue() { // 取得该Cookie的值
return this.value;
}
public int getVersion() { // 拿到该Cookie使用的版本号
return this.version;
}
public void setVersion(int v) { // 设置该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC2109规范
this.version = v;
}
public Object clone() { // 克隆方法
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public void setHttpOnly(boolean httpOnly) { // 如果在Cookie中设置了"HttpOnly"属性,那么通过JavaScript脚本将无法读取到Cookie信息,
// 这样能有效的防止XSS攻击,让网站应用更加安全。
this.httpOnly = httpOnly;
}
public boolean isHttpOnly() {
return this.httpOnly;
}
}
在这个包下,org.apache.catalina.connector.Response;里面有一个addCookie()方法,用于在响应头增加一个相应的Set-Cookie头字段。
public void addCookie(Cookie cookie) {
if ((this.included) || (isCommitted())) {
return;
}
String header = generateCookieString(cookie);
addHeader("Set-Cookie", header, getContext().getCookieProcessor()
.getCharset());
}
在org.apache.catalina.connector.Request;里面有个getCookies()方法,用于获取客户端提交的Cookie.
public Cookie[] getCookies() {
if (!this.cookiesConverted) {
convertCookies();
}
return this.cookies;
}
具体例子:(下面是为了说明问题,不可运行)
package com.dialog.test;
import javax.servlet.http.Cookie;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
public class TestDialog {
public static void main(String[] args) {
Cookie cookie = new Cookie("zhouyi", "");
Response response = new Response();
response.addCookie(cookie);
Request request = new Request();
request.getCookies();
}
}
cookie禁用问题的解决方式:1,给出提示,开启cookie ; 2 , URL重写,必须对网站的所有地址重写。
HttpSession API
问题抛出:我们浏览网页,比如买东西的历史纪录,总是给出最新的历史纪录。是如何做到,存的显然是对象,
这时候就可以利用session对象,一个浏览器独占一格session对象。(购物车的实现以及登陆验证,待写)。
定义如是:javax.servlet.http.HttpSession;源码如下:
public abstract interface HttpSession {
public abstract long getCreationTime(); // 获取session创建时间,是格林尼治时间。
public abstract String getId(); // 获取sessionID
public abstract long getLastAccessedTime(); // 获得最后一次访问session的时间。
public abstract ServletContext getServletContext(); // 获取Servlet上下文,已经废弃
public abstract void setMaxInactiveInterval(int paramInt); // 设置session的有效时间,有生命周期的
public abstract int getMaxInactiveInterval(); // 获取session的有效时间
/**
* @deprecated
*/
public abstract HttpSessionContext getSessionContext(); // 返回 session 在其中得以保持的环境变量。 这个方法和其他所有
// HttpSessionContext 的方法一样被取消了。
public abstract Object getAttribute(String paramString); // 设置单个属性
/**
* @deprecated
*/
public abstract Object getValue(String paramString); // 根据name拿到value值,已经废弃
public abstract Enumeration<String> getAttributeNames(); // 获得多个name属性
/**
* @deprecated
*/
public abstract String[] getValueNames(); // 拿到多个value值,已经废弃
public abstract void setAttribute(String paramString, Object paramObject); // 设置
/**
* @deprecated
*/
public abstract void putValue(String paramString, Object paramObject);// 已经废弃
public abstract void removeAttribute(String paramString); // 移除name
/**
* @deprecated
*/
public abstract void removeValue(String paramString); // 移除value,已经废弃
public abstract void invalidate(); // 使session销毁,默认自动销毁30分钟。也可以使用配置文件设置销毁时间
public abstract boolean isNew(); // 返回一个布尔值以判断这个 session 是不是新的
}
在org.apache.catalina.connector.Request;中有getSession方法。
public HttpSession getSession() {
Session session = doGetSession(true);
if (session == null) {
return null;
}
return session.getSession();
}
getSession()执行原理:
1,获取名称为JSESSIONID的cookie值
2,如果没有这样的cookie,创建一个新的HttpSession对象,分配一个唯一的SessionID。并向客服端编写一个名字为JSESSIONID = SessionID的cookie.
3,如果有这样的cookie,获取cookie的值(即HttpSession对象的值),从服务器的内存中根据ID找到那个HttpSession对象:找到了,取出继续为您服务。若早不到,回到2重新开始。
getSession(boolean create): 参数为true和上面一样;参数为false,根据JSESSIONID的cookie值,找到对应的HttpSession对象,找不到则返回null,这个不会创建新的,只是起了查询的作用。
(使用Session实现一次性验证码,待写(一中已经写过一部分))
测试例子:
@RequestMapping("/testCookieAndSession")
@ResponseBody
public String testCookieAndSession(HttpServletResponse response,HttpServletRequest request,HttpSession session) {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); // 错误500 (Internal Server Error)解决方案
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Allow-Credentials","true");
response.setContentType("application/json");
response.addCookie(new Cookie("zhouyi", "18329jdd"));
TestUser usr = new TestUser();
usr.setTestUserNo(123);
usr.setTestUserName("周毅");
usr.setTestUserSex("男");
session.setAttribute("TestUser", usr);
return "cookie";
}
postman结果和网页访问结果:
网页: