0x01 前言
??HTTP 為無狀態(tài)協(xié)議娃豹,協(xié)議對于事務(wù)處理沒有記憶能力山析。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息奶是,則它必須重傳。另一方面聚磺,在服務(wù)器不需要先前信息時(shí)它的應(yīng)答就較快饲齐。客戶端與服務(wù)器進(jìn)行動態(tài)交互的 Web 應(yīng)用程序出現(xiàn)之后咧最,HTTP 無狀態(tài)的特性嚴(yán)重阻礙了這些應(yīng)用程序的實(shí)現(xiàn),畢竟交互是需要承前啟后的御雕,簡單的購物車程序也要知道用戶到底在之前選擇了什么商品矢沿。于是,兩種用于保持 HTTP 連接狀態(tài)的技術(shù)就應(yīng)運(yùn)而生了酸纲,一個是 Cookie捣鲸,而另一個則是 Session。
0x02 Cookie
??Cookie闽坡,有時(shí)也用其復(fù)數(shù)形式 Cookies栽惶,指某些網(wǎng)站為了辨別用戶身份、進(jìn)行 session 跟蹤而儲存在用戶本地終端上的數(shù)據(jù)(通常經(jīng)過加密)疾嗅。
0x03 Session
??Session外厂,稱為“會話控制”。Session 對象存儲特定用戶會話所需的屬性及配置信息代承。這樣汁蝶,當(dāng)用戶在應(yīng)用程序的 Web 頁之間跳轉(zhuǎn)時(shí),存儲在 Session 對象中的變量將不會丟失论悴,而是在整個用戶會話中一直存在下去掖棉。當(dāng)用戶請求來自應(yīng)用程序的 Web 頁時(shí),如果該用戶還沒有會話膀估,則 Web 服務(wù)器將自動創(chuàng)建一個 Session 對象幔亥。當(dāng)會話過期或被放棄后,服務(wù)器將終止該會話察纯。Session 對象最常見的一個用法就是存儲用戶的首選項(xiàng)帕棉。
0x04 Java 操作 Cookie
Java 操作 Cookie 步驟
Cookie cookie = new Cookie(String name, String value); // 創(chuàng)建 Cookie 對象 cookie,name 為名捐寥,value 為值
resp.addCookie(cookie); // 將 cookie 發(fā)送給瀏覽器笤昨,由瀏覽器保存
Cookie[] cookies = req.getCookies(); // 獲取 HTTP request 中 cookie,Cookie 類型的數(shù)組形式保存
構(gòu)建登陸表單
創(chuàng)建用于登陸表單 login.html
<body>
<form action="/myweb/cookie/login" method="post">
<p><input type="text" name="username" placeholder="用戶名" /></p>
<p><input name="password" name="password" placeholder="密碼" /></p>
<p><input type="submit" value="提交表單" /></p>
</form>
</body>
創(chuàng)建瀏覽器本地 Cookie
??接收 login.html 提交的登陸參數(shù)賬號和密碼握恳,req.getParamter()
方法接收 request 提交的參數(shù)并賦值給 String 類型變量 username
和 password
瞒窒,創(chuàng)建 Cookie 對象 userCookie
和 passCookie
并逐一發(fā)送給瀏覽器。
@WebServlet(urlPatterns = "/cookie/login")
public class LoginCookieServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter(); // 頁面內(nèi)容輸出對象
String username = req.getParameter("username"); // 1乡洼、捕捉表單提交參數(shù)
String password = req.getParameter("password");
Cookie userCookie = new Cookie("username", username); // 2崇裁、創(chuàng)建 cookie
Cookie passCookie = new Cookie("password", password);
resp.addCookie(userCookie); // 3匕坯、發(fā)送 cookie 到客戶端
resp.addCookie(passCookie);
// TODO 其他操作
}
}
0x05 服務(wù)端獲取 Cookie 進(jìn)行處理
??reqs.getCookies()
獲取 Cookie 類型數(shù)組 Cookie[] cookies
,由cookie.getName()
獲取 Cookie 的名稱拔稳,根據(jù)名稱進(jìn)行進(jìn)一步操作葛峻。
@WebServlet(urlPatterns = "/cookie/handler")
public class HandlerCookieServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter(); // 頁面內(nèi)容輸出對象
String username = null;
String password = null;
Cookie[] cookies = req.getCookies(); // 1、創(chuàng)建 cookie
if (cookies != null) { // 2巴比、處理 cookie
for (Cookie cookie : cookies) {
String key = cookie.getName();
if ("username".equals(key)) {
username = cookie.getValue();
}
if ("password".equals(key)) {
password = cookie.getValue();
}
}
}
// TODO 進(jìn)行其他操作
}
}
0x06 Java 操作 Session
Java 操作 Session 步驟:
HttpSession session = req.getSession(boolean create); // Session 的創(chuàng)建和獲取
session.setAttribute(String name, Object value); // Session 存儲數(shù)據(jù)
String username = session.getAttribute(String name); // Session 獲取數(shù)據(jù)
session.removeAttribute(String name); // Session 刪除某個屬性值术奖,name 為屬性的名稱
session.invalidate(); // 銷毀 Session 對象
session.setMaxInactiveInterval(60 * 10); // 超過10分鐘,銷毀 session
??HttpSession session = req.getSession(boolean create);
當(dāng) create
為 true
時(shí)轻绞,判斷 Session 對象是否存在采记,存在則返回該 Session 對象,不存在則創(chuàng)建一個新的session
政勃。當(dāng) create
為 false
時(shí)唧龄,不存在則返回 null
。
Session的創(chuàng)建奸远、獲取和操作
  接收 login.html 提交的登陸參數(shù)賬號和密碼既棺,利用 JavaBean規(guī)范創(chuàng)建 User 類,將 `username` 和 `password` 存儲在JavaBean規(guī)范生成對象中懒叛。`req.geetSession()` 創(chuàng)建 Session 對象 `session`丸冕,session 以屬性名標(biāo)識session "USER_IN_SESSION" 對應(yīng)值 `user`。
@WebServlet("/session/login")
public class LoginSessionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
User user = new User(username, password);
HttpSession session = req.getSession(); // 1薛窥、創(chuàng)建Session
session.setAttribute("USER_IN_SESSION", user); // 2晨仑、創(chuàng)建Session對象
session.removeAttribute("USER_IN_SESSION"); // 3、刪除指定session屬性
session.invalidate(); // 4拆檬、銷毀session
session.setMaxInactiveInterval(60 * 10); // 5洪己、超過10分鐘無操作則銷毀session
// TODO 進(jìn)行其他操作
}
}
Session 獲取具體操作
??req.getSession()
創(chuàng)建和獲取 session 對象, session.getAttribute("USER_IN_SESSION")
獲取強(qiáng)轉(zhuǎn)為 User 類對象 user
調(diào)用 getter 獲取 username
竟贯,password
答捕。
@WebServlet(urlPatterns="/session/handler")
public class DetailSessionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
HttpSession session = req.getSession();// 1、創(chuàng)建和獲取 Session
User user = (User) session.getAttribute("USER_IN_SESSION"); // 2屑那、處理 Session
String username = user.getUsername(); // 3拱镐、獲取對象后調(diào)用 getter 取值
String password = user.getPassword();
}
}
0x07 Java 操作 Cookie 其他細(xì)節(jié)
Cookie 原理
??第一次請求時(shí),服務(wù)器將 cookie 發(fā)送到瀏覽器持际,瀏覽器進(jìn)行保存沃琅,下次請求時(shí),瀏覽器將 cookie 通過 request 對象發(fā)送到服務(wù)器蜘欲。
Cookie 支持中文存儲
Cookie userCookie = new Cookie("username", URLEncoder.encode(username, "UTF-8")); // 使用 URLEncoder 編碼
username = URLDecoder.decode(cookie.getValue(), "UTF-8"); // 使用 URLDecoder 解碼
??String username = req.getParameter("username")
接收 username
應(yīng)考慮為 GET 提交還是 POST 提交益眉,因?yàn)楫?dāng)提交 username 為中文時(shí),注意編碼是否為 UTF-8 以規(guī)避亂碼問題。
會話 Cookie 和持久化 Cookie
??會話 Cookie:生命周期伴隨著會話的開始和結(jié)束郭脂。
??持久化 Cookie:生命周期與會話的開始和結(jié)束無關(guān)年碘。
cookie.setMaxAge(int expiry);
// expiry > 0 持久化 cookie
// expriy = 0 刪除該 cookie
// expriy < 0 會話 cookie,默認(rèn)值為 -1
Cookie 作用域
不同主機(jī)不共享 cookie展鸡。
希望不同的二級域名中可以共享 Cookie屿衅,那么就要設(shè)置 Cookie 的 domain 和 path 了。
??例如:music.baidu.com莹弊、map.baidu.com涤久、tieba.baidu.com,它們的域名不同忍弛,但百度希望它們之間可以共享 Cookie拴竹。
設(shè)置 Cookie 的 path 為 "/" ,例如:
cookie.setPath("/")
在整個 baidu.com 中都能傳遞剧罩。設(shè)置 Cookie 的 domain,例如:
cookie.setDomain(".baidu.com")
座泳,其中 domain 中沒有指定域名前綴惠昔!在 music.baidu.com 主機(jī)中的某個項(xiàng)目中保存了 Cookie。
在 map.baidu.com 主機(jī)中某個項(xiàng)目中獲取 Cookie挑势。
0x08 Java 操作 Session 其他細(xì)節(jié)
命名規(guī)則
??一般來說镇防,Session 我習(xí)慣命名為“XX_IN_SESSION”例如:USER_IN_SESSION
。
使用 JavaBean 對象
??若需要把多個數(shù)據(jù)存放到 Session 中潮饱,就得調(diào)用 setAttribute()
N次来氧。一般的,我們把需要存儲的數(shù)據(jù)香拉,封裝成一個對象啦扬,然后在存儲到 Session 中。例如:把用戶的信息凫碌,封裝到 User 對象 user
扑毡,再賦給 session。例如:session.setAttribute("USER_IN_SESSION", user);
網(wǎng)絡(luò)共享 Session
??如果多臺服務(wù)器之間需要共享 Session 盛险,此時(shí) Session 中的對象瞄摊,必須實(shí)現(xiàn) java.io.Serializable(序列化)。
URL 帶 Session
??當(dāng)瀏覽器禁用 Cookie 之后需要手動攜帶 Session 的 ID苦掘,通過鏈接 url + jessionid 進(jìn)行手動攜帶session。例如: String url = http://www.baidu.com/example;jesession=session.session.getId();