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

一個Cookie只能記住一個信息。
@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)建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
// 2.調用response的一個方法把Cookie傳給客戶端
response.addCookie(cookie);
}
}
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方法,它用于在發(fā)送給瀏覽器的HTTP響應消息中增加一個Set-Cookie響應頭字段。
HttpServletRequest接口中定義了一個getCookies方法,它用于從HTTP請求消息的Cookie請求頭字段中讀取所有的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(沒有單獨獲取某一個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)建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
// 2.調用response的一個方法Cookie傳給客戶端
response.addCookie(cookie);
}
}else{
out.print("no Cookie,create one and return");
// 1.創(chuàng)建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
// 2.調用response的一個方法Cookie傳給客戶端
response.addCookie(cookie);
}
}
}
如果創(chuàng)建了一個cookie,并將他發(fā)送到瀏覽器,默認情況下它是一個會話級別的cookie; 存儲在瀏覽器的內存中,用戶退出瀏覽器之后被刪除。若希望瀏覽器將該cookie存儲在磁盤上,則需要使用maxAge,并給出一個以秒為單位的時間。將最大時效設為0則是命令瀏覽器刪除該cookie。
發(fā)送cookie需要使用HttpServletResponse的addCookie方法,將cookie插入到一個 Set-Cookie HTTP響應報頭中。由于這個方法并不修改任何之前指定的Set-Cookie報頭,而是創(chuàng)建新的報頭,因此將這個方法稱為是addCookie,而非setCookie。
setMaxAge(秒)設置Cookie的最大時效,若為0代表立即上除該Cookie,若為負數表述不存儲該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(沒有單獨獲取某一個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)建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
cookie.setMaxAge(200);
// 2.調用response的一個方法Cookie傳給客戶端
response.addCookie(cookie);
}
}else{
out.print("no Cookie,create one and return");
// 1.創(chuàng)建一個Cookie對象
Cookie cookie = new Cookie("name","neusoft");
cookie.setMaxAge(200);
// 2.調用response的一個方法Cookie傳給客戶端
response.addCookie(cookie);
}
}
}
課堂案例--1:
利用Cookie進行自動登錄
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">進入后臺</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 = "";
// 沒有得到參數,遍歷看是否有
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");
// 獲取到參數,設置最大時效,發(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問題
@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(沒有單獨獲取某一個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");
}
}
}
運行是讀取不到的,路徑調換一下,可以讀到
Cookie的作用范圍:可以作用當前目錄和當前目錄的子目錄,但不能作用與當前目錄的上一級目錄
如何解決:
@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小結
(1)簡介
Cookie機制采用的是在客戶端保持 HTTP 狀態(tài)信息的方案。
Cookie實際上是一小段的文本信息。客戶端請求服務器,如果服務器需要記錄該用戶狀態(tài),就使用response向客戶端瀏覽器頒發(fā)一個Cookie??蛻舳藶g覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態(tài)。
(2)作用
Cookie的根本作用就是在客戶端存儲用戶訪問網站的一些信息。典型的應用有:
自動登錄。
(3)缺陷
①Cookie會被附加在每個HTTP請求中,所以無形中增加了流量。
②由于在HTTP請求中的Cookie是明文傳遞的,所以安全性成問題。(除非用HTTPS)
③Cookie的大小限制在4KB左右。對于復雜的存儲需求來說是不夠用的。
(4)常用方法
創(chuàng)建Cookie:Cookie cookie = new Cookie(name,value)
向瀏覽器發(fā)送Cookie:response.addCookie(cookie)
設置最大時效:cookie.setMaxAge(秒),當設置為0的時候,使用response.addCookie(cookie),表示刪除該cookie。