Java 編程之 Cookie & Session

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 類型變量 usernamepassword 瞒窒,創(chuàng)建 Cookie 對象 userCookiepassCookie 并逐一發(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) createtrue 時(shí)轻绞,判斷 Session 對象是否存在采记,存在則返回該 Session 對象,不存在則創(chuàng)建一個新的session政勃。當(dāng) createfalse 時(shí)唧龄,不存在則返回 null

Session的創(chuàng)建奸远、獲取和操作

&#8195;&#8195;接收 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拴竹。

  1. 設(shè)置 Cookie 的 path 為 "/" ,例如:cookie.setPath("/") 在整個 baidu.com 中都能傳遞剧罩。

  2. 設(shè)置 Cookie 的 domain,例如:cookie.setDomain(".baidu.com")座泳,其中 domain 中沒有指定域名前綴惠昔!

  3. 在 music.baidu.com 主機(jī)中的某個項(xiàng)目中保存了 Cookie。

  4. 在 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();

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市找爱,隨后出現(xiàn)的幾起案子清蚀,更是在濱河造成了極大的恐慌,老刑警劉巖递瑰,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跳座,死亡現(xiàn)場離奇詭異端铛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)疲眷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門禾蚕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狂丝,你說我怎么就攤上這事换淆。” “怎么了几颜?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵倍试,是天一觀的道長。 經(jīng)常有香客問我蛋哭,道長县习,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任谆趾,我火速辦了婚禮躁愿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘沪蓬。我一直安慰自己彤钟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布跷叉。 她就那樣靜靜地躺著逸雹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪云挟。 梳的紋絲不亂的頭發(fā)上梆砸,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音园欣,去河邊找鬼辫樱。 笑死,一個胖子當(dāng)著我的面吹牛俊庇,可吹牛的內(nèi)容都是我干的狮暑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辉饱,長吁一口氣:“原來是場噩夢啊……” “哼搬男!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起彭沼,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缔逛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褐奴,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡按脚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了敦冬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辅搬。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖脖旱,靈堂內(nèi)的尸體忽然破棺而出堪遂,到底是詐尸還是另有隱情,我是刑警寧澤萌庆,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布溶褪,位于F島的核電站,受9級特大地震影響践险,放射性物質(zhì)發(fā)生泄漏猿妈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一巍虫、第九天 我趴在偏房一處隱蔽的房頂上張望彭则。 院中可真熱鬧,春花似錦垫言、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至前痘,卻和暖如春凛捏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芹缔。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工坯癣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人最欠。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓示罗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親芝硬。 傳聞我的和親對象是個殘疾皇子蚜点,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容