# Cookie
在程序中,會話跟蹤是很重要的事情。理論上,一個用戶的所有請求操作都應該屬于同一個會話,而另一個用戶的所有請求操作則應該屬于另一個會話,二者不能混淆。例如,用戶A在超市購買的任何商品都應該放在A的購物車內,不論是用戶A什么時間購買的,這都是屬于同一個會話的,不能放入用戶B或用戶C的購物車內,這不屬于同一個會話。
而Web應用程序是使用HTTP協議傳輸數據的。HTTP協議是無狀態的協議。一旦數據交換完畢,客戶端與服務器端的連接就會關閉,再次交換數據需要建立新的連接。這就意味著服務器無法從連接上跟蹤會話。即用戶A購買了一件商品放入購物車內,當再次購買商品時服務器已經無法判斷該購買行為是屬于用戶A的會話還是用戶B的會話了。要跟蹤該會話,必須引入一種機制。
Cookie就是這樣的一種機制。它可以彌補HTTP協議無狀態的不足。在Session出現之前,基本上所有的網站都采用Cookie來跟蹤會話。
***
在 Servlet 規范中,常用以下兩種機制完成會話跟蹤
#### Cookie
#### Session
***
### Cookie機制
cookie機制采用的是**在客戶端保持 HTTP 狀態信息的方案。**
Cookie意為“甜餅”,是由W3C組織提出,最早由Netscape社區發展的一種機制。目前Cookie已經成為標準,所有的主流瀏覽器如IE、Netscape、Firefox、Opera等都支持Cookie。
由于HTTP是一種無狀態的協議,服務器單從網絡連接上無從知道客戶身份。怎么辦呢?就給客戶端們頒發一個通行證吧,每人一個,無論誰訪問都必須攜帶自己通行證。這樣服務器就能從通行證上確認客戶身份了。這就是Cookie的工作原理。
Cookie實際上是一小段的文本信息。客戶端請求服務器,如果服務器需要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。
一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。
#### Cookie的傳送過程示意圖

演示代碼
~~~
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!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>
<%
// 在JavaWEB規范中使用Cookie類代表cookie
// 1.創建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
// 2.調用response的一個方法把Cookie傳給客戶端
response.addCookie(cookie);
%>
</body>
</html>
~~~
Servlet API中提供了一個javax.servlet.http.Cookie類來封裝Cookie信息,它包含有生成Cookie信息和提取Cookie信息的各個屬性的方法。
Cookie類的方法:
--構造方法: public Cookie(String name,String value)
--**getName**方法
--setValue與**getValue**方法
--**setMaxAge**與**getMaxAge**方法
--**setPath**與getPath方法
HttpServletResponse接口中定義了一個addCookie方法,它用于在發送給瀏覽器的HTTP響應消息中增加一個Set-Cookie響應頭字段。
HttpServletRequest接口中定義了一個getCookies方法,它用于從HTTP請求消息的Cookie請求頭字段中讀取所有的Cookie項。
~~~
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!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>
<%
// 1.獲取 Cookie(沒有單獨獲取某一個Cookie的方法)
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length >= 1){
for(Cookie cookie:cookies){
// 獲取Cookie的name和value
out.print(cookie.getName()+":"+cookie.getValue());
out.print("<br>");
}
}else{
out.print("沒有一個Cookie,正在創建并返回");
// 1.創建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
// 2.調用response的一個方法Cookie傳給客戶端
response.addCookie(cookie);
}
%>
</body>
</html>
~~~
如果創建了一個cookie,并將他發送到瀏覽器,**默認情況下它是一個會話級別的cookie; 存儲在瀏覽器的內存中,用戶退出瀏覽器之后被刪除**。若希望瀏覽器將該cookie存儲在磁盤上,則需要使用maxAge,并給出一個以秒為單位的時間。將最大時效設為0則是命令瀏覽器刪除該cookie。
發送cookie需要使用HttpServletResponse的addCookie方法,將cookie插入到一個 Set-Cookie HTTP響應報頭中。由于這個方法并不修改任何之前指定的Set-Cookie報頭,而是創建新的報頭,因此將這個方法稱為是addCookie,而非setCookie。
#### setMaxAge(秒)設置Cookie的最大時效,若為0代表立即上除該Cookie,若為負數表述不存儲該Cookie
~~~
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!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>
<%
// 在JavaWEB規范中使用Cookie類代表cookie
// 1.創建一個Cookie對象
/* Cookie cookie = new Cookie("name","neusoft"); */
// 2.調用response的一個方法把Cookie傳給客戶端
/*response.addCookie(cookie); */
// 1.獲取 Cookie
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length >= 1){
for(Cookie cookie:cookies){
// 獲取Cookie的name和value
out.print(cookie.getName()+":"+cookie.getValue());
out.print("<br>");
}
}else{
out.print("沒有一個Cookie,正在創建并返回");
// 1.創建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
cookie.setMaxAge(20);
// 2.調用response的一個方法Cookie傳給客戶端
response.addCookie(cookie);
}
%>
</body>
</html>
~~~
***
課堂案例--1:
利用Cookie進行自動登錄
autoLogin.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>
<form action="index.jsp" method="post">
username:<input type="text" name="username">
<input type="submit" value="確定">
</form>
</body>
</html>
~~~
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>
<%
String username = request.getParameter("username");
// 獲取到參數,設置最大時效,發給瀏覽器
if(username != null && !username.trim().equals("")){
Cookie cookie = new Cookie("username",username);
cookie.setMaxAge(30);
response.addCookie(cookie);
}else{
// 沒有得到參數,遍歷看是否有
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("")){
out.print("Hello:"+username);
}else{
response.sendRedirect("autoLogin.jsp");
}
%>
</body>
</html>
~~~
***
課堂案例--2:
顯示最近瀏覽的 5 本書的 title

books.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>
<h1>Books Page</h1>
<a href="book.jsp?book=JavaWeb">JavaWeb</a><br><br>
<a href="book.jsp?book=Java">Java</a><br><br>
<a href="book.jsp?book=Oracle">Oracle</a><br><br>
<a href="book.jsp?book=Ajax">Ajax</a><br><br>
<a href="book.jsp?book=JavaScript">JavaScript</a><br><br>
<a href="book.jsp?book=Android">Android</a><br><br>
<a href="book.jsp?book=Struts">Struts</a><br><br>
<a href="book.jsp?book=Spring">Spring</a><br><br>
<a href="book.jsp?book=Jbpm">Jbpm</a><br><br>
<a href="book.jsp?book=Hibernate">Hibernate</a><br><br>
<br><br>
<%
Cookie cookies[] = request.getCookies();
if(cookies != null && cookies.length > 0){
for(Cookie cookie:cookies){
if(cookie.getName().startsWith("neusoft_book_")){
%>
<%= cookie.getValue() %>
<%
}
}
}
%>
</body>
</html>
~~~
book.jsp
~~~
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ 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>
<h1>Book Detail Page</h1>
<% String book = request.getParameter("book"); %>
Book:<%= book %>
<br><br>
<a href="books.jsp">Return...</a>
<%
// 獲取Cookie數組
Cookie cookies[] = request.getCookies();
// 存放以neusoft_book_開頭的cookie
List<Cookie> cookieList = new ArrayList<Cookie>();
Cookie tempCookie = null;
// 遍歷,找到以neusoft_book_開頭的cookie保存到集合當中
if(cookies != null && cookies.length > 0){
for(Cookie c:cookies){
String cookieName = c.getName();
if(cookieName.startsWith("neusoft_book_")){
cookieList.add(c);
if(c.getValue().equals(book)){
tempCookie = c;
}
}
}
}
if(cookieList.size() >= 5 && tempCookie == null){
tempCookie = cookieList.get(0);
}
if(tempCookie != null){
tempCookie.setMaxAge(0);
response.addCookie(tempCookie);
}
// 要添加的Cookie
Cookie cookie = new Cookie("neusoft_book_"+book,book);
response.addCookie(cookie);
%>
</body>
</html>
~~~
***
課堂實例--3:保存用戶名密碼
NewFile.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>
<%
Cookie cookies[] = request.getCookies();
String username = "";
String password = "";
if(cookies != null && cookies.length > 0){
for(Cookie c:cookies){
if(c.getName().equals("username")){
username = c.getValue();
}
if(c.getName().equals("password")){
password = c.getValue();
}
}
}
%>
<form action="second.jsp" method="post">
UserName:<input type="text" name="username" value="<%= username %>"><br><br>
Password:<input type="password" name="password" value="<%= password %>"><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
~~~
second.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>
<%
String username = (String)request.getParameter("username");
String password = (String)request.getParameter("password");
if(username != null && password != null && !username.trim().equals("") && !password.trim().equals("")){
out.print("hello:"+username);
Cookie cookie1 = new Cookie("username",username);
Cookie cookie2 = new Cookie("password",password);
cookie1.setMaxAge(20);
cookie2.setMaxAge(20);
response.addCookie(cookie1);
response.addCookie(cookie2);
}else{
response.sendRedirect("20160123/NewFile.jsp");
}
%>
</body>
</html>
~~~
***
### Cookie的Path問題
/20180119/writecookie.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>
<%
Cookie cookie = new Cookie("cookiePath","Value");
response.addCookie(cookie);
%>
<a href="../readcookie.jsp">To Read</a>
</body>
</html>
~~~
/readcookie.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>
<%
String cookieValue = null;
Cookie cookies[] = request.getCookies();
if(cookies != null && cookies.length > 0){
for(Cookie cookie:cookies){
if(cookie.getName().equals("cookiePath")){
cookieValue = cookie.getValue();
}
}
}
if(cookieValue != null){
out.print(cookieValue);
}else{
out.print("沒有指定的Value");
}
%>
</body>
</html>
~~~
運行是讀取不到的,路徑調換一下,可以讀到
Cookie的作用范圍:可以作用當前目錄和當前目錄的子目錄,但不能作用與當前目錄的上一級目錄
如何解決:
/20180119/writecookie.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>
<%
Cookie cookie = new Cookie("cookiePath","Value");
// 設置cookie的作用范圍
cookie.setPath(request.getContextPath());
response.addCookie(cookie);
%>
<a href="../readcookie.jsp">To Read</a>
</body>
</html>
~~~
## Cookie小結
#### (1)簡介
Cookie機制采用的是在客戶端保持 HTTP 狀態信息的方案。
Cookie實際上是一小段的文本信息。客戶端請求服務器,如果服務器需要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。
#### (2)作用
Cookie的根本作用就是在客戶端存儲用戶訪問網站的一些信息。典型的應用有:
1、記住密碼,下次自動登錄。
2、購物車功能。
3、記錄用戶瀏覽數據,進行商品(廣告)推薦。
#### (3)缺陷
①Cookie會被附加在每個HTTP請求中,所以無形中增加了流量。
②由于在HTTP請求中的Cookie是明文傳遞的,所以安全性成問題。(除非用HTTPS)
③Cookie的大小限制在4KB左右。對于復雜的存儲需求來說是不夠用的。
#### (4)常用方法
創建Cookie:Cookie cookie = new Cookie(name,value)
向瀏覽器發送Cookie:response.addCookie(cookie)
設置最大時效:cookie.setMaxAge(秒),當設置為0的時候,使用response.addCookie(cookie),表示刪除該cookie。
- 第一章 配置和安裝Tomcat
- 第二章 Servlet(一)
- 第三章 Servlet(二)
- 練習 一 . Servlet配置級獲取初始化參數
- 第四章 JSP(一)
- 第五章 JSP(二)
- 第六章 MVC設計模式
- 第七章 Cookie
- 第八章 Session
- 練習 二 . 簡易版購物車
- 第九章 EL表達式
- 第十章 JSTL
- 第十一章 過濾器
- 第十二章 監聽器
- 第十三章 文件的上傳與下載
- 復習總結
- 如何手動啟動Tomcat
- 如何修改Tomcat端口號
- 如何在web.xml中配置Servlet
- Servlet生命周期
- load-on-startup參數
- Servlet映射路徑
- POST和GET的區別
- JSP中9個隱式對象及功能
- 請求轉發及請求重定向的區別
- JSP指令有哪些
- 簡述對MVC設計模式的理解
- 簡述Cookie機制
- 簡述Session機制
- HttpSession的生命周期
- Cookie和Session有什么區別
- 簡述創建過濾器步驟
- 過濾器經典案例--統一編碼字符集
- getParameter與getAttribute的區別
- JSP頁面中可以包含哪些元素
- web應用中,是如何跟蹤用戶的
- InteliJ創建web項目