一、簡介
http協議是無狀態的,在web會話中,為了記錄會話狀態資訊,將使用cookie和session,這裡基於原始碼進行介紹。
二、cookie
cookie是servlet發給客戶端瀏覽器的小量資訊,並由瀏覽器儲存,後續瀏覽器請求將會帶上前面儲存的資訊。cookie通常用於標識使用者身份。一個cookie有名稱、值和其它可選屬性(如備註、路徑、域名標識、最大存活時間、版本號等)。
2.1 cookie特點
1、瀏覽器通常對每個web服務支援20個cookie,並且瀏覽器總共支援300個cookie(換句話說,極端情況,瀏覽器最多支援15個web服務的cookie);
2、一個cookie通常限制4KB;
3、使用HttpServletResponse.addCookie方法新增cookie;
4、使用HttpServletRequest.getCookies方法獲取cookie;
5、不同路徑下cookie可以有相同名稱;
6、cookie返回瀏覽器時儲存在響應header中。
2.2 cookie原始碼
Cookie原始碼如下:
package javax.servlet.http;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
public class Cookie implements Cloneable, Serializable {
//cookie名稱,其中$Name形式為保留字
private String name;
//cookie值
private String value;
//cookie備註
private String comment;
//域名,指定在哪個域名有效
private String domain;
//不設定表示同瀏覽器程序一樣的存活時間
private int maxAge = -1;
//路徑,表示cookie對指定路徑及子路徑有效,不設定表示瀏覽器訪問所路徑都帶上cookie,同時伺服器任何路徑回傳都不帶cookie資訊
private String path;
//是否使用SSL,是則只有在安全方式訪問傳送cookie,否則可以以非安全方式訪問傳送
private boolean secure;
//版本,等於1表示RFC2109++型別
private int version = 0;
//是否http只讀,即只能http或https訪問傳輸,如javascript等不能訪問
private boolean isHttpOnly = false;
//cookie構造器,填充名稱和值,其中名稱不能是保留字,忽略大小寫,
//保留字有Comment、Discard、Domain、Expires、Max-Age、Path、Secure、Version、以$開頭
public Cookie(String name, String value) {}
//各屬性值的get和set方法,略過
...
}
2.3 cookie示例
cookie讀取與新增示例如下:
package session;
import com.alibaba.fastjson.JSON;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
public class CookieServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("this is cookie");
Cookie idCookie = null;
String id = req.getParameter("id");
//獲取cookie
Cookie[] cookies = req.getCookies();
if (null != cookies && cookies.length > 0) {
idCookie = Arrays.stream(cookies).filter(t -> "c_id".equals(t.getName())).findFirst().orElse(null);
resp.getWriter().write(JSON.toJSONString(idCookie));
}
//新增cookie
idCookie = new Cookie("c_id", Objects.toString(id, "default"));
idCookie.setComment("cookie test");
idCookie.setDomain("dragon.com");
idCookie.setPath("/");
idCookie.setHttpOnly(true);
resp.addCookie(idCookie);
}
}
三、session
session與cookie相反,session是在服務端儲存狀態資訊,藉助cookie或重寫url的方式傳遞會話標識。在整個會話過程中,瀏覽器只需傳遞sessionId即可,服務端根據sessionId識別請求是哪個客戶端。
3.1 session特點
1、session會話資訊保存於服務端的記憶體中,使用HttpSession儲存;
2、客戶端第一次訪問服務端,需要會話時,才會建立session;
3、會話HttpSession物件有唯一sessionId,唯一標識客戶端,客戶端每次請求都要帶上;
4、session會話有儲存時間,單位是分鐘,預設為30,配置位於tomcat/conf/web.xml中的session-timout中;
5、使用HttpServletRequest.getSession(boolean create)獲取HttpSession,引數create為true時,沒有則新建session,另外過載方法HttpServletRequest.getSession()即是引數為true;
3.2 HttpSession原始碼
HttpSession原始碼如下:
package javax.servlet.http;
import java.util.Enumeration;
import javax.servlet.ServletContext;
public interface HttpSession {
//返回session的建立時間,單位是毫秒(自1970年1月1日GMT)
public long getCreationTime();
//返回session的唯一id
public String getId();
//返回session的最後訪問時間,單位是毫秒(自1970年1月1日GMT)
public long getLastAccessedTime();
//返回session所屬的ServletContext
public ServletContext getServletContext();
//設定session最長空閒時間,單位毫秒,超過則結束會話,值為0或負數則永不過期
public void setMaxInactiveInterval(int interval);
//獲取session最長空閒時間,單位毫秒
public int getMaxInactiveInterval();
//獲取指定名稱物件,沒有則返回null
public Object getAttribute(String name);
//獲取繫結物件名稱
public Enumeration<String> getAttributeNames();
//新增物件,若物件為null,則移出
//若物件實現HttpSessionBindingListener介面,則HttpSessionBindingListener.valueUnbound方法會被呼叫
//若指定名稱已經綁定了物件,則繫結物件被替換,如果繫結物件實現HttpSessionBindingListener介面,則繫結物件HttpSessionBindingListener.valueUnbound方法會被呼叫
public void setAttribute(String name, Object value);
//移出物件,若移出物件實現HttpSessionBindingListener介面,則移出物件HttpSessionBindingListener.valueUnbound方法會被呼叫
public void removeAttribute(String name);
//強制HttpSession失效,結束會話
public void invalidate();
//判斷當前session是否是新建的,true是,false否,
public boolean isNew();
}
3.3 session示例
會話中待存物件User.java:
import com.alibaba.fastjson.JSON;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class User implements HttpSessionBindingListener {
public String userId;
public User(String userId) {
this.userId = userId;
}
@Override
public void valueBound(HttpSessionBindingEvent event) {
Object obj = event.getValue();
System.out.println("bound,value:" + JSON.toJSONString(obj));
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
Object obj = event.getSource();
System.out.println("unbound,new value:" + JSON.toJSONString(obj));
}
}
會話servlet:
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class SessionServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("this is session");
String userId = req.getParameter("userId");
HttpSession session = req.getSession();
if(StringUtils.isNotBlank(userId)){
session.setAttribute("user", new User(userId));
}
resp.getWriter().write(JSON.toJSONString(session.getAttribute("user")));
}