HTTP协议是无状态的的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。Cookie和Seesion,就是这样的机制,可以弥补HTTP协议的无状态的不足。
Cookie是客户端技术,程序把每个客户的数据以Cookie的形式写给用户各自的浏览器。当用户私用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样web资源处理的就是用户各自的数据了。
Session是服务器端技术,服务器在运行时可以为每个用户的浏览器创建一个其独享的Session对象,由于Session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的资源放在各自的Session中,当用户再去访问服务器中的其他web资源时,其他web资源再从用户各自的Session中取出数据为用户服务。
一、Cookie基础
1、工作原理:
HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户的身份。Cookie就像是给客户端颁发的一个通行证。每个客户浏览器一个,无论谁访问必须携带自己的通行证。这样服务器就能从通行证上确认客户身份了。
2、基本知识:
1)Cookie是保存在客户端的内容,每个浏览器有各自的编号,区分浏览器,浏览器不同,信息不共享。
2)写入的信息只能是文本文档。不支持中文,如支持,必须使用从新转码。
3)客户端可以阻止服务器写入。
4)Cookie不能跨域名。服务器只能拿自己的web应用写入的东西。
5)浏览器的Cookie数量是有限的,大概是30-50个,每个为4K左右,每个浏览器各有不同。
3、实现:
1)客户端请求服务器,可以使用 response 向客户端浏览器颁发一个Cookie。客户端会把Cookie保存起来。当浏览器再去访问该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查Cookie,以此来辨认用户状态。服务器还可以根据需要修改 Cookie 的内容。
2)可以在浏览器地址栏数据 javascript:alert(document.cookie) 就可以了。document.cookie获取所有的。
二、Cookie操作
1、基本知识:
1)java中把Cookie封装成javax.servlet.http.Cookie类。服务器通过操作Cookie类对象对客户端Cookie进行操作。
2)Cookie对象使用key-value 属性对的形式保存用户状态。一个 request 或者 response 同时使用多个Cookie。
3)创建Cookie :Cookie cookie = new Cookie(String key, String value)。如果key和value为中文(Unicode字符),需要使用URLEncoder进行编码。如果为二进制,则需要使用Base64编码。
4)向客户端设置Cookie : response.addCookie(Cookie cookie) 。
5)获取客户端的Cookie : Cookie[] cookies = request.getCookies()(以Cookie[]数组形式返回)。
6)获取Cookie 的name和value: String tName = Cookie.getName(); String tValue = Cookie.getValue();
7)设置Cookie的时间 : cookie.setMaxAge(maxAge); 值的类型:
A、正数:表示Cookie在maxAge之后失效,cookieChina.setMaxAge(Integer.MAX_VALUE)-永久有效
B、负数(-1):临时Cookie,浏览器关闭即失效,不保存。-1是默认值。
C、0-删除该Cookie。Cookie没有删除的方法,可以设置maxage为0;修改Cookie: 可以添加一个同名的Cookie用于覆盖前一个来修改Cookie。
8)Cookie的域名: Domain属性(IE是禁止的,会有安全问题)。
A、Cookie具有不可跨域名性。www.gogle.com 和 www.baidu.com不可交互Cookie。同一域名下两个二级域名 如 http://www.baidu.com 和 http://music.baidu.com 也 不同交互使用Cookie。如果想所有的 baidu.com 名下的二级域名都可以使用该 Cookie, 需要设置Domain属性
B、Domain属性,必须以(“.”)开始。另外,name相同但是domain 不同的两个Cookie是两个不同的Cookie。
C、如果想要两个域名完全不同的网站共有 Cookie, 可以生成两个Cookie, domain属性分别为两个域名,输出到客户端。
9)Cookie的路径: path属性
A、path属性决定了访问Cookie的路径,即contextPath路径。例如,如果只允许/JavaWeb/下的程序使用Cookie,可以这么写:
B、path属性必须以“/XXX/”这种形式,当只有“/”时,表示所有路径都可以访问该Cookie。
C、一个Servlet/JSP 设置的cookie 只能被与这个Servlet/JSP在同一路径下或子路径下的Servlet/JSP访问。父路径和其他路径无法获取。如sesson/test/b.jsp可以获取到路径session/a.jsp的 Cookie,而不能获取/session/b/的Cookie。
D、这边的路径不是指文件的存放真实路径,而是指url路径,是指<url-pattern>设置的路径。
- // 6-Cookie的路径
- Cookie cookie4 = new Cookie("time","201401008");
- cookie4.setPath("/Javaweb/");//只有Javaweb/下的可以访问
- response.addCookie(cookie4);
10)Cookie的安全属性:secure属性
如果不希望Cookie在HTTP等非安全协议中传输,可以设置cookie的secure属性属性为true。浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie。
- // 7-Cookie的安全属性
- Cookie cookie5 = new Cookie("time","201401008");
- cookie5.setSecure(true);//true,在HTTP中无法获取本Cookie
2、JS操作Cookie:
1)格式:在js中Cookie的格式:account=111; ssid=222; JSESSIONID=7E99EBDC3CA63AB849D1493FBCCC5159,类似于map类型。
2)获取:document.cookie获取所有的Cookie。
3)获取单个固定的Cookie,可以自己封装方法:
4)、创建Cookie的方法,我们也可以封装成一个方法:
3、Jquery操作Cookie:需要下载jquery.cookie.js,使用起来非常方便。
1)简单设置Cookie : 设置一个name-Cookie的名字,value-Cookie的值。
- $.cookie("name", "value");
2)设置其他参数:
- //设置完整的cookie
- $.cookie("name", "sam-sho",{
- expires : 10,//有效期,单位为天
- path : "/",
- domain : "jquery.com"
- secrue : true
- });
- //设置精细的时间
- var cookietime = new Date();
- cookietime.setTime(date.getTime() + (60 * 60 * 1000));//coockie保存一小时
- $.cookie("sam", "sam-sho",{expires:cookietime});
3)读取Cookie :读取名字为sam的Cookie。
- $.cookie("sam")
4)删除Cookie :删除名称为 sam 的Cookie,只要把value设置成null。注意:必须使用与之前设置的相同的路径(path)和域名(domain),才能正确删除。
- $.cookie("sam",null);
三、实际案例。
1、实例1::永久登录。
1)纯JSP实现:
2、实例2: 使用Cookie统计UV量。2)使用Servlet实现较为麻烦,MD5的公共方法等略。如下:
A、LoginCookieServlet: 负责记录Cookie的servlet。Post提交表单后,servlet把写两个cookie到客户端。一是账户的cookie,另一个是账户加密后的cookie。然后重定向到CheckCookieServlet,校验。一定要用重定向,确保客户端使用两次请求。由于加密的key是服务器独有的,是安全的。
- package servlet.cookie;
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.log4j.Logger;
- import util.MD5Utils;
- /**
- *
- * LoginCookieServlet.java
- *
- * @title 永久登录 登录的servlet
- * @description
- * @author SAM-SHO
- * @Date 2014-10-10
- */
- public class LoginCookieServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- private Logger logger = Logger.getLogger(this.getClass());
- // 密钥
- private static final String KEY = ":[email protected]";//可以放配置文件
- public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- this.doPost(request, response);
- }
- /**
- * post方法访问,处理永久登录
- */
- public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- request.setCharacterEncoding("UTF-8");
- response.setCharacterEncoding("UTF-8");
- String action = request.getParameter("action");
- if ("login".equals(action)) {
- String account = request.getParameter("account");
- // String password = request.getParameter("password");
- int timeout = new Integer(request.getParameter("timeout"));
- // 把帐号连同密钥使用MD5后加密后保存
- String ssid = MD5Utils.calcMD5(account + KEY);
- // 把帐号保存到Cookie中 并控制有效期
- Cookie accountCookie = new Cookie("account", account);//中文需要编码
- accountCookie.setMaxAge(timeout);
- // 把加密结果保存到Cookie中 并控制有效期
- Cookie ssidCookie = new Cookie("ssid", ssid);
- ssidCookie.setMaxAge(timeout);
- response.addCookie(accountCookie);// 账户Cookie
- response.addCookie(ssidCookie);// 加密后账户的Cookie
- logger.debug(accountCookie.getName()+"++++++++"+accountCookie.getValue());
- logger.debug(ssidCookie.getName()+"+++++++"+ ssidCookie.getValue());
- // 重定向到校验servlet
- // 使用两个request,这样访问到校验的request就带有了本次response写入的cookie。
- response.sendRedirect(this.getServletContext().getContextPath() + "/servlet/CheckCookieServlet");
- return;
- }
- }
- }
B、LoginoutCookieServlet:注销的servlet,负责删除cookie。然后校验。其实可以和LoginCookieServlet进行合并。
- package servlet.cookie;
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- /**
- *
- * LoginoutCookieServlet
- *
- * @title 永久登录-注销的servlet
- * @description
- * @author SAM-SHO
- * @Date 2014-10-10
- */
- public class LoginoutCookieServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- this.doPost(request, response);
- }
- /**
- * post方法访问,处理注销,删除Cookie
- */
- public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- request.setCharacterEncoding("UTF-8");
- response.setCharacterEncoding("UTF-8");
- String action = request.getParameter("action");
- if ("logout".equals(action)) {
- // 删除Cookie中的帐号
- Cookie accountCookie = new Cookie("account", "");
- accountCookie.setMaxAge(0);
- // 删除Cookie中的加密结果
- Cookie ssidCookie = new Cookie("ssid", "");
- ssidCookie.setMaxAge(0);
- response.addCookie(accountCookie);
- response.addCookie(ssidCookie);
- // 重定向到校验servlet
- response.sendRedirect(this.getServletContext().getContextPath() + "/servlet/CheckCookieServlet");
- return;
- }
- }
- }
C、CheckCookieServlet:负责校验。
- package servlet.cookie;
- import java.io.IOException;
- import java.util.Arrays;
- import javax.servlet.ServletException;
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.log4j.Logger;
- import util.MD5Utils;
- /**
- *
- * CheckCookieServlet.java
- *
- * @title 用于校验
- * @description
- * @author SAM-SHO
- * @Date 2014-10-11
- */
- public class CheckCookieServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- private Logger logger = Logger.getLogger(this.getClass());
- // 密钥
- private static final String KEY = ":[email protected]";//可以放配置文件
- public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- this.doPost(request, response);
- }
- /**
- * 校验
- */
- public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- request.setCharacterEncoding("UTF-8");
- response.setCharacterEncoding("UTF-8");
- boolean loggin = false;
- String account = null;
- String ssid = null;
- // 获取Cookie中的account与ssid
- Cookie[] cookies = request.getCookies();
- if(cookies!= null){
- logger.debug("所有的Cookies : " + Arrays.asList(cookies));
- for(Cookie cookie : cookies){
- if((cookie.getName()).equals("account"))
- account = cookie.getValue();
- if((cookie.getName()).equals("ssid"))
- ssid = cookie.getValue();
- }
- }
- if(account != null && ssid != null){
- // 如果加密规则正确, 则视为已经登录
- loggin = ssid.equals(MD5Utils.calcMD5(account + KEY));
- }
- logger.debug("是否匹配 : "+ loggin);
- request.getSession(true).setAttribute("loggin", loggin);
- // 跳转到页面
- request.getRequestDispatcher("/view/cookie/jsp/loginCookie.jsp").forward(request, response);
- // response.sendRedirect(this.getServletContext().getContextPath() +"/view/cookie/jsp/loginCookie.jsp");
- return;
- }
- }
D、loginCookie.jsp:显示页面。
- <%@ page language="java" pageEncoding="UTF-8" isErrorPage="false"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
- <c:set var="base" value="${pageContext.request.contextPath}" />
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>
- <c:choose>
- <c:when test="${loggin==true}">欢迎您回来</c:when>
- <c:otherwise>请先登录</c:otherwise>
- </c:choose>
- </title>
- <link rel="stylesheet" type="text/css" href="${base}/css/style.css">
- <script type="text/javascript" src="${base}/js/jquery-1.7.2.js"></script>
- <script type="text/javascript" src="${base}/view/cookie/js/cookie.js"></script>
- </head>
- <body>
- <div align="center" style="margin: 10px;">
- <fieldset>
- <legend>
- 当前有效的 Cookie
- </legend>
- <script>
- document.write(document.cookie);
- </script>
- </fieldset>
- <fieldset>
- <legend>
- <c:choose>
- <c:when test="${loggin ==true}">
- 欢迎您回来
- </c:when>
- <c:otherwise>
- 请先登录
- </c:otherwise>
- </c:choose>
- </legend>
- <c:choose>
- <c:when test="${loggin==true}">
- 欢迎您, ${cookie.account.value }
- <a href="${base}/servlet/LoginoutCookieServlet?action=logout">注 销</a>
- </c:when>
- <c:otherwise>
- <form action="${base}/servlet/LoginCookieServlet?action=login"
- method="post">
- <table>
- <tr>
- <td>
- 帐号:
- </td>
- <td>
- <input type="text" name="account" style="width: 200px;">
- </td>
- </tr>
- <tr>
- <td>
- 密码:
- </td>
- <td>
- <input type="password" name="password" style="width: 200px;">
- </td>
- </tr>
- <tr>
- <td>
- 有效期:
- </td>
- <td>
- <input type="radio" name="timeout" value="-1" checked>
- 关闭浏览器即失效
- <br />
- <input type="radio" name="timeout"
- value="<%=30 * 24 * 60 * 60%>">
- 30天内有效
- <br />
- <input type="radio" name="timeout"
- value="<%=Integer.MAX_VALUE%>">
- 永久有效
- <br />
- </td>
- </tr>
- <tr>
- <td>
- </td>
- <td>
- <input type="submit" value=" 登 录 " class="button">
- </td>
- </tr>
- </table>
- </form>
- </c:otherwise>
- </c:choose>
- </fieldset>
- </div>
- </body>
- <script type="text/javascript">
- var account = CookieJs.getCookie("account");
- var ssid = CookieJs.getCookie("ssid");
- alert(account);
- alert(ssid);
- </script>
- </html>