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ò)程示意圖
一個(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。