Cookie

Cookie

在程序中背镇,會(huì)話跟蹤是很重要的事情咬展。理論上泽裳,一個(gè)用戶的所有請(qǐng)求操作都應(yīng)該屬于同一個(gè)會(huì)話糙申,而另一個(gè)用戶的所有請(qǐng)求操作則應(yīng)該屬于另一個(gè)會(huì)話犬钢,二者不能混淆。例如掌栅,用戶A在超市購(gòu)買的任何商品都應(yīng)該放在A的購(gòu)物車內(nèi)祷舀,不論是用戶A什么時(shí)間購(gòu)買的瀑梗,這都是屬于同一個(gè)會(huì)話的,不能放入用戶B或用戶C的購(gòu)物車內(nèi)裳扯,這不屬于同一個(gè)會(huì)話夺克。

而Web應(yīng)用程序是使用HTTP協(xié)議傳輸數(shù)據(jù)的。HTTP協(xié)議是無(wú)狀態(tài)的協(xié)議嚎朽。一旦數(shù)據(jù)交換完畢铺纽,客戶端與服務(wù)器端的連接就會(huì)關(guān)閉,再次交換數(shù)據(jù)需要建立新的連接哟忍。這就意味著服務(wù)器無(wú)法從連接上跟蹤會(huì)話狡门。即用戶A購(gòu)買了一件商品放入購(gòu)物車內(nèi),當(dāng)再次購(gòu)買商品時(shí)服務(wù)器已經(jīng)無(wú)法判斷該購(gòu)買行為是屬于用戶A的會(huì)話還是用戶B的會(huì)話了锅很。要跟蹤該會(huì)話其馏,必須引入一種機(jī)制。

Cookie就是這樣的一種機(jī)制爆安。它可以彌補(bǔ)HTTP協(xié)議無(wú)狀態(tài)的不足叛复。在Session出現(xiàn)之前,基本上所有的網(wǎng)站都采用Cookie來(lái)跟蹤會(huì)話扔仓。

在 Servlet 規(guī)范中褐奥,常用以下兩種機(jī)制完成會(huì)話跟蹤

Cookie
Session

Cookie機(jī)制

cookie機(jī)制采用的是在客戶端保持 HTTP 狀態(tài)信息的方案。

Cookie意為“甜餅”翘簇,是由W3C組織提出撬码,最早由Netscape社區(qū)發(fā)展的一種機(jī)制。目前Cookie已經(jīng)成為標(biāo)準(zhǔn)版保,所有的主流瀏覽器如IE呜笑、Netscape、Firefox彻犁、Opera等都支持Cookie叫胁。

由于HTTP是一種無(wú)狀態(tài)的協(xié)議,服務(wù)器單從網(wǎng)絡(luò)連接上無(wú)從知道客戶身份汞幢。怎么辦呢驼鹅?就給客戶端們頒發(fā)一個(gè)通行證吧,每人一個(gè),無(wú)論誰(shuí)訪問(wèn)都必須攜帶自己通行證谤民。這樣服務(wù)器就能從通行證上確認(rèn)客戶身份了。這就是Cookie的工作原理疾宏。

Cookie實(shí)際上是一小段的文本信息张足。客戶端請(qǐng)求服務(wù)器坎藐,如果服務(wù)器需要記錄該用戶狀態(tài)为牍,就使用response向客戶端瀏覽器頒發(fā)一個(gè)Cookie⊙意桑客戶端瀏覽器會(huì)把Cookie保存起來(lái)碉咆。當(dāng)瀏覽器再請(qǐng)求該網(wǎng)站時(shí),瀏覽器把請(qǐng)求的網(wǎng)址連同該Cookie一同提交給服務(wù)器蛀恩。服務(wù)器檢查該Cookie疫铜,以此來(lái)辨認(rèn)用戶狀態(tài)。

一個(gè)Cookie只能標(biāo)識(shí)一種信息双谆,它至少含有一個(gè)標(biāo)識(shí)該信息的名稱(NAME)和設(shè)置值(VALUE)壳咕。

Cookie的傳送過(guò)程示意圖

image.png

一個(gè)Cookie只能記住一個(gè)信息。

@WebServlet("/cookie")
public class CookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 在JavaWEB規(guī)范中使用Cookie類代表cookie
        // 1.創(chuàng)建一個(gè)Cookie對(duì)象
        Cookie cookie = new Cookie("name","neusoft");
        // 2.調(diào)用response的一個(gè)方法把Cookie傳給客戶端
        response.addCookie(cookie);
    }
}

Servlet API中提供了一個(gè)javax.servlet.http.Cookie類來(lái)封裝Cookie信息顽馋,它包含有生成Cookie信息和提取Cookie信息的各個(gè)屬性的方法谓厘。

Cookie類的方法:
--構(gòu)造方法: public Cookie(String name,String value)
--getName方法
--setValue與getValue方法
--setMaxAge與getMaxAge方法
--setPath與getPath方法

HttpServletResponse接口中定義了一個(gè)addCookie方法,它用于在發(fā)送給瀏覽器的HTTP響應(yīng)消息中增加一個(gè)Set-Cookie響應(yīng)頭字段寸谜。
HttpServletRequest接口中定義了一個(gè)getCookies方法竟稳,它用于從HTTP請(qǐng)求消息的Cookie請(qǐng)求頭字段中讀取所有的Cookie項(xiàng)。

@WebServlet("/GetCookieServlet")
public class GetCookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        // 1.獲取 Cookie(沒有單獨(dú)獲取某一個(gè)Cookie的方法)
        Cookie[] cookies = request.getCookies();
        if(cookies != null && cookies.length >= 1){
            boolean bFind = false;
            for(Cookie cookie:cookies){
                if(cookie.getName().equals("name"))
                {
                    bFind = true;
                }
            }
            if(bFind)
            {
                out.print("neusoft Cookie exist");
            }
            else {
                out.print("no Cookie,create one and return");
                // 1.創(chuàng)建一個(gè)Cookie對(duì)象
                Cookie cookie = new Cookie("name","neusoft");

                // 2.調(diào)用response的一個(gè)方法Cookie傳給客戶端
                response.addCookie(cookie);
            }
        }else{
            out.print("no Cookie,create one and return");
            // 1.創(chuàng)建一個(gè)Cookie對(duì)象
            Cookie cookie = new Cookie("name","neusoft");

            // 2.調(diào)用response的一個(gè)方法Cookie傳給客戶端
            response.addCookie(cookie);
        }
    }
}

如果創(chuàng)建了一個(gè)cookie熊痴,并將他發(fā)送到瀏覽器他爸,默認(rèn)情況下它是一個(gè)會(huì)話級(jí)別的cookie; 存儲(chǔ)在瀏覽器的內(nèi)存中,用戶退出瀏覽器之后被刪除果善。若希望瀏覽器將該cookie存儲(chǔ)在磁盤上讲逛,則需要使用maxAge,并給出一個(gè)以秒為單位的時(shí)間岭埠。將最大時(shí)效設(shè)為0則是命令瀏覽器刪除該cookie盏混。

發(fā)送cookie需要使用HttpServletResponse的addCookie方法,將cookie插入到一個(gè) Set-Cookie HTTP響應(yīng)報(bào)頭中惜论。由于這個(gè)方法并不修改任何之前指定的Set-Cookie報(bào)頭许赃,而是創(chuàng)建新的報(bào)頭,因此將這個(gè)方法稱為是addCookie馆类,而非setCookie混聊。

setMaxAge(秒)設(shè)置Cookie的最大時(shí)效,若為0代表立即上除該Cookie乾巧,若為負(fù)數(shù)表述不存儲(chǔ)該Cookie

@WebServlet("/GetCookieServlet")
public class GetCookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        // 1.獲取 Cookie(沒有單獨(dú)獲取某一個(gè)Cookie的方法)
        Cookie[] cookies = request.getCookies();
        if(cookies != null && cookies.length >= 1){
            boolean bFind = false;
            for(Cookie cookie:cookies){
                if(cookie.getName().equals("name"))
                {
                    bFind = true;
                }
            }
            if(bFind)
            {
                out.print("neusoft Cookie exist");
            }
            else {
                out.print("no Cookie,create one and return");
                // 1.創(chuàng)建一個(gè)Cookie對(duì)象
                Cookie cookie = new Cookie("name","neusoft");
                cookie.setMaxAge(200);
                // 2.調(diào)用response的一個(gè)方法Cookie傳給客戶端
                response.addCookie(cookie);
            }
        }else{
            out.print("no Cookie,create one and return");
            // 1.創(chuàng)建一個(gè)Cookie對(duì)象
            Cookie cookie = new Cookie("name","neusoft");
            cookie.setMaxAge(200);
            // 2.調(diào)用response的一個(gè)方法Cookie傳給客戶端
            response.addCookie(cookie);
        }
    }
}

課堂案例--1:
利用Cookie進(jìn)行自動(dòng)登錄
index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Insert title here</title>
</head>
<body>
  <a href="admin.do">進(jìn)入后臺(tái)</a>
</body>
</html>

admin.do

@WebServlet("/admin.do")
public class AdminServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = "";
                // 沒有得到參數(shù)句喜,遍歷看是否有
        Cookie cookies[] = request.getCookies();

        if(cookies != null && cookies.length > 0){
            for(Cookie cookie:cookies){
                String cookieName = cookie.getName();
                if(cookieName.equals("username")){
                    username = cookie.getValue();
                }
            }
        }
        if(username != null && !username.trim().equals("")){
            response.getWriter().print("Hello:"+username);
        }else{
            response.sendRedirect("login.jsp");
        }
    }
}

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="login.do" method="post">
    username:<input type="text" name="username">
    <input type="submit" value="確定">
</form>
</body>
</html>

login.do

@WebServlet("/login.do")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        String username = request.getParameter("username");
        // 獲取到參數(shù)预愤,設(shè)置最大時(shí)效,發(fā)給瀏覽器
        if(username != null && !username.trim().equals("")){
            Cookie cookie = new Cookie("username",username);
            cookie.setMaxAge(300);
            response.addCookie(cookie);
            response.getWriter().print("Hello:"+username);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

Cookie的Path問(wèn)題

@WebServlet("/path/PathServlet")
public class PathServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("name","neusoft");
        response.addCookie(cookie);
    }
}
@WebServlet("/GetCookieServlet")
public class GetCookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        // 1.獲取 Cookie(沒有單獨(dú)獲取某一個(gè)Cookie的方法)
        Cookie[] cookies = request.getCookies();
        if(cookies != null && cookies.length >= 1){
            boolean bFind = false;
            for(Cookie cookie:cookies){
                if(cookie.getName().equals("name"))
                {
                    bFind = true;
                }
            }
            if(bFind)
            {
                out.print("neusoft Cookie exist");
            }
            else {
                out.print("no Cookie,create one and return");
            }
        }else{
            out.print("no Cookie,create one and return");
        }
    }
}

運(yùn)行是讀取不到的咳胃,路徑調(diào)換一下植康,可以讀到
Cookie的作用范圍:可以作用當(dāng)前目錄和當(dāng)前目錄的子目錄,但不能作用與當(dāng)前目錄的上一級(jí)目錄
如何解決:

@WebServlet("/path/PathServlet")
public class PathServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("name","neusoft");
        cookie.setPath("/");
        response.addCookie(cookie);
    }
}

${pageContext.request.contextPath}

<a href="${pageContext.request.contextPath}/sport/view.do"></a>

cookie.setPath("/");

Cookie小結(jié)

(1)簡(jiǎn)介
Cookie機(jī)制采用的是在客戶端保持 HTTP 狀態(tài)信息的方案展懈。

Cookie實(shí)際上是一小段的文本信息销睁。客戶端請(qǐng)求服務(wù)器存崖,如果服務(wù)器需要記錄該用戶狀態(tài)冻记,就使用response向客戶端瀏覽器頒發(fā)一個(gè)Cookie±淳澹客戶端瀏覽器會(huì)把Cookie保存起來(lái)冗栗。當(dāng)瀏覽器再請(qǐng)求該網(wǎng)站時(shí),瀏覽器把請(qǐng)求的網(wǎng)址連同該Cookie一同提交給服務(wù)器供搀。服務(wù)器檢查該Cookie贞瞒,以此來(lái)辨認(rèn)用戶狀態(tài)。

(2)作用
Cookie的根本作用就是在客戶端存儲(chǔ)用戶訪問(wèn)網(wǎng)站的一些信息趁曼。典型的應(yīng)用有:

自動(dòng)登錄军浆。

(3)缺陷
①Cookie會(huì)被附加在每個(gè)HTTP請(qǐng)求中,所以無(wú)形中增加了流量挡闰。

②由于在HTTP請(qǐng)求中的Cookie是明文傳遞的乒融,所以安全性成問(wèn)題。(除非用HTTPS)

③Cookie的大小限制在4KB左右摄悯。對(duì)于復(fù)雜的存儲(chǔ)需求來(lái)說(shuō)是不夠用的赞季。

(4)常用方法
創(chuàng)建Cookie:Cookie cookie = new Cookie(name,value)

向?yàn)g覽器發(fā)送Cookie:response.addCookie(cookie)

設(shè)置最大時(shí)效:cookie.setMaxAge(秒),當(dāng)設(shè)置為0的時(shí)候奢驯,使用response.addCookie(cookie)申钩,表示刪除該cookie。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瘪阁,一起剝皮案震驚了整個(gè)濱河市撒遣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌管跺,老刑警劉巖义黎,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異豁跑,居然都是意外死亡廉涕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)狐蜕,“玉大人宠纯,你說(shuō)我怎么就攤上這事〔闶停” “怎么了婆瓜?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)湃累。 經(jīng)常有香客問(wèn)我勃救,道長(zhǎng)碍讨,這世上最難降的妖魔是什么治力? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮勃黍,結(jié)果婚禮上宵统,老公的妹妹穿的比我還像新娘。我一直安慰自己覆获,他們只是感情好马澈,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著弄息,像睡著了一般痊班。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上摹量,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天涤伐,我揣著相機(jī)與錄音,去河邊找鬼缨称。 笑死凝果,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的睦尽。 我是一名探鬼主播器净,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼当凡!你這毒婦竟也來(lái)了山害?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沿量,失蹤者是張志新(化名)和其女友劉穎粗恢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欧瘪,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡眷射,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妖碉。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涌庭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出欧宜,到底是詐尸還是另有隱情坐榆,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布冗茸,位于F島的核電站席镀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夏漱。R本人自食惡果不足惜豪诲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挂绰。 院中可真熱鬧屎篱,春花似錦、人聲如沸葵蒂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)践付。三九已至秦士,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間永高,已是汗流浹背隧土。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乏梁,地道東北人次洼。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像遇骑,于是被迫代替她去往敵國(guó)和親卖毁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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