會(huì)話(huà)?
web應(yīng)用程序的請(qǐng)求與響應(yīng)是基于HTTP昆稿,為無(wú)狀態(tài)通信協(xié)議问裕,服務(wù)器不會(huì)維護(hù)上一次請(qǐng)求和下一次請(qǐng)求之間的關(guān)系,然而有些功能是必須由多次請(qǐng)求完成的鸠删,例如購(gòu)物車(chē):用戶(hù)可能在多個(gè)物品頁(yè)面采購(gòu)物品贫导,web應(yīng)用程序必須要有個(gè)方式來(lái)得知用戶(hù)在這些網(wǎng)頁(yè)中采購(gòu)了哪些商品抛猫,這種維護(hù)上一次請(qǐng)求和下一次請(qǐng)求間關(guān)系的方式,就成為會(huì)話(huà)管理(Session Management)
使用Cookie實(shí)現(xiàn)會(huì)話(huà)管理
Cookie是瀏覽器存儲(chǔ)信息的一種方式孩灯,服務(wù)器可以設(shè)置響應(yīng)頭set-cookie闺金,瀏覽器接收然后將該頭部傳輸過(guò)來(lái)的數(shù)據(jù)以文件的形式存儲(chǔ)在本地
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 {
String prop = System.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING");
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();
}
}
}
// cookie就是瀏覽器維護(hù)的key-value數(shù)據(jù)
Cookie cookie = new Cookie("id", "233PcDdXD#");
//設(shè)置cookie的有效期,以秒為單位钱反,默認(rèn)是關(guān)閉瀏覽器就失效掖看,這里是一個(gè)星期
cookie.setMaxAge(7 * 24 * 60 * 60);
// 設(shè)置cookie只允許在 https 協(xié)議下使用
cookie.setSecure(true);
// 設(shè)置cookie不能被瀏覽器腳本(js)獲取,能在一定程度上防止XSS攻擊
cookie.setHttpOnly(true);
// response.addCookie()其實(shí)就是給響應(yīng)頭set-cookie添加值
response.addCookie(cookie);
// request可以獲取到該網(wǎng)頁(yè)所屬域中的所有cookie
Cookie[] cookies = request.getCookies();
// 操作cookie中的數(shù)據(jù)
if (cookies != null) {
for (Cookie cook :cookies) {
String key = cook.getName();
String value = cook.getValue();
}
}
HttpSession
public interface HttpSession {
long getCreationTime();
String getId();
long getLastAccessedTime();
ServletContext getServletContext();
void setMaxInactiveInterval(int var1);
int getMaxInactiveInterval();
/** @deprecated */
HttpSessionContext getSessionContext();
Object getAttribute(String var1);
/** @deprecated */
Object getValue(String var1);
Enumeration<String> getAttributeNames();
/** @deprecated */
String[] getValueNames();
void setAttribute(String var1, Object var2);
/** @deprecated */
void putValue(String var1, Object var2);
void removeAttribute(String var1);
/** @deprecated */
void removeValue(String var1);
void invalidate();
boolean isNew();
}
// 1面哥、創(chuàng)建會(huì)話(huà)
HttpSession session = request.getSession();
// 2、通過(guò)會(huì)話(huà)傳遞對(duì)象
session.setAttribute("key","value");
// 3毅待、獲取會(huì)話(huà)中被傳遞的對(duì)象
session.getAttribute("key");
// 4尚卫、刪除會(huì)話(huà)中被傳遞的對(duì)象
session.removeAttribute("key");
// 5、刪除會(huì)話(huà)
session.invalidate();
HttpSession原理
1. 當(dāng)通過(guò)請(qǐng)求對(duì)象創(chuàng)建當(dāng)前Session對(duì)象的時(shí)候尸红,web容器會(huì)為每個(gè)Session對(duì)象分配一個(gè)標(biāo)識(shí)ID吱涉,稱(chēng)作Session ID刹泄,可以通過(guò)session.getId()獲取,該Session ID默認(rèn)會(huì)使用Cookie存放在瀏覽器中怎爵,當(dāng)web容器時(shí)tomcat的時(shí)候特石,該Session ID在Cookie的名字是JSESSIONID
// 每個(gè)session都會(huì)有個(gè)標(biāo)識(shí)ID,默認(rèn)會(huì)存放在Cookie中鳖链,在tomcat中名稱(chēng)是JSEESIONID
String sessionId = session.getId();
2. 當(dāng)瀏覽器發(fā)送請(qǐng)求時(shí)姆蘸,會(huì)將Cookie存放的Session ID一并發(fā)送過(guò)去,這樣子web容器就可以根據(jù)Session ID來(lái)找出對(duì)應(yīng)HttpSession對(duì)象芙委,這樣就可以區(qū)分各個(gè)瀏覽器中不同的會(huì)話(huà)了
3. Cookie中存放的JSESSIONID默認(rèn)在瀏覽器關(guān)閉的時(shí)候失效逞敷,重啟瀏覽器的時(shí)候,將會(huì)得到一個(gè)新的JSESSIONID
4. 默認(rèn)關(guān)閉瀏覽器會(huì)馬上消失的是瀏覽器上的Cookie灌侣,而不是服務(wù)器中的HttpSession推捐;要想HttpSession立即失效必須運(yùn)行invalidate()方法,否則的話(huà)侧啼,HttpSession會(huì)等到設(shè)定的時(shí)間到才會(huì)被銷(xiāo)毀牛柒,設(shè)定的時(shí)間可以在程序中設(shè)置,也可以在web部署表述符中配置痊乾,一般都會(huì)選擇后者
4.1 在程序中設(shè)置
// 會(huì)話(huà)不被使用自動(dòng)失效時(shí)間焰络,時(shí)間單位是:秒
session.setMaxInactiveInterval(233);
4.2 在we部署描述符中設(shè)置
<session-config>
<!-- 不被使用的Session失效時(shí)間,時(shí)間單位:分鐘 -->
<session-timeout>7</session-timeout>
<!-- Servlet3.0新特性符喝,設(shè)置Session ID在Cookie中的屬性 -->
<cookie-config>
<!-- 自定義Session ID闪彼,在tomcat中默認(rèn)名JSESSIONID -->
<name>xixihaha</name>
<!-- 定義存儲(chǔ)Session ID的Cookie存活時(shí)間,單位是秒 -->
<max-age>30</max-age>
</cookie-config>
</session-config>
當(dāng)禁用瀏覽器中的Cookie時(shí)协饲,會(huì)把Session ID追加在URL后畏腕;當(dāng)瀏覽器第一次請(qǐng)求網(wǎng)站時(shí),web容器并不知道瀏覽器是否禁用Cookie茉稠,所以也會(huì)把Session ID添加在URL后一并發(fā)送
小心保管Session ID描馅,只要有人取得當(dāng)次的Session ID,在另一瀏覽器相同的URL附上Session ID而线,就可以取得同一個(gè) HttpSession對(duì)象