Cookei详解

Cookie简介

Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。 目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。 怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。 这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

Cookie实际上是一小段的文本信息。 客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。 客户端浏览器会把Cookie保存起来。 当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。 服务器检查该Cookie,以此来辨认用户状态。 服务器还可以根据需要修改Cookie的内容。

Cookie机制

Cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端, 然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。

具体过程如下:

  1. 用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;

  2. 服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体 (Response Body)中的,而是存放于HTTP响应头(Response Header)

  3. 客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置。 对于Windows操作系统而言,我们可以从: [系统盘]:\Documents and Settings[用户名]\Cookies目录中找到存储的Cookie;

  4. 客户端再次向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。 而这次,Cookie信息则存放在HTTP请求头(equest Header)了。

HTTP的Cookie机制

Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。 一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。 这就意味着服务器无法从连接上跟踪会话。 举个例子,用户A购买了一件商品放入购物车内, 当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。 要跟踪该会话,必须引入一种机制。 ​
Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。 在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话

Set-Cookie和Cookie

两个Http头部和Cookie有关 : Set-Cookie和Cookie

当服务器返回给客户端一个Http响应信息时,其中如果包含Set-Cookie这个头部,说明:

  1. 指示客户端建立一个cookie

  2. 在后续的Http请求中自动发送这个cookie到服务器端,直到这个cookie过期。

  3. 如果cookie的生存时间是整个会话期间的话,那么浏览器会将 cookie 保存在内存中, 浏览器关闭时就会自动清除这个cookie。

  4. 如果将 cookie 保存在客户端的硬盘中,浏览器关闭的话,该 cookie 也不会被清除, 下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。

一个cookie的设置以及发送过程分为以下四步:

    1. 客户端发送一个http请求到服务器端
    1. 服务器端发送一个http响应到客户端,其中包含Set-Cookie头部
    1. 客户端发送一个http请求到服务器端,其中包含Cookie头部
    1. 服务器端发送一个http响应到客户端

在客户端的第二次请求中包含Cookie头部,提供给了服务器端可以用来唯一标识客户端身份的信息。 这时,服务器端也就可以判断客户端是否启用了cookie。 尽管,用户可能在和应用程序交互的过程中突然禁用cookie的使用, 但是,这个情况基本是不太可能发生的,所以可以不加以考虑,这在实践中也被证明是对的。

Cookie的不可跨域名性

很多网站都会使用Cookie。例如,Google会向客户端颁发Cookie,Baidu也会向客户端颁发Cookie。 那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?

答案是否定的。Cookie具有不可跨域名性。 根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。 Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。

Cookie在客户端是由浏览器来管理的。 浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。 浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。 Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。

  • 注意:

虽然网站images.google.com与网站www.google.com同属于Google, 但是域名不一样,二者同样不能互相操作彼此的Cookie。

用户登录网站www.google.com之后会发现访问images.google.com时登录信息仍然有效,而普通的Cookie是做不到的。 这是因为Google做了特殊处理。

简单案例 : 记录上次访问时间

cookie的API

new Cookie(String key,String value);
String getName();//获取cookie的key(名称)
String getValue();//获取cookie的值
void setMaxAge(int);//设置cookie在浏览器存活时间,单位:秒
//如果设置成0:表示删除高cookie(前提:路径必须一致)
void setPath(String path);//设置cookie的路径
//当我们访问的路径中包含次cookie的path,才会携带cookie
//默认访问路径:访问Servlet的路径,从"/项目名称"开始,到最后一个"/"结束。比如:/demo/a/b,默认路径为/demo/a
//手动设置路径:以"/项目名称"开始,以"/"结尾

写回浏览器

response.addCookie(Cookie);

获取cookie

Cookie[] request.getCookies();
  • 核心代码:
/**
 * 根据 cookie名称获取Cookie 的工具类
 */
public class CookieUtils {
    public static Cookie getCookieByName(String name,Cookie[] cookies){
        if(cookies != null){
            for(Cookie cookie : cookies){
                if(name.equals(cookie.getName())){
                    return cookie;
                }
            }
        }
        return null;
    }
}
public class RecordServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
        response.setContentType("text/html;charset=utf-8");
        PrintWriter w = response.getWriter();

        //2.获取指定名称的Cookie
        Cookie cookie = CookieUtils.getCookieByName("record",request.getCookies());

        //3.判断cookie是否为空;
        // 若为null,则说明是第一次访问;
        // 若不为 null,则根据cookie显示上一次的访问时间
        if(cookie == null){
            w.write("这是您第一次访问");
        }else{
            long lastTime= Long.parseLong(cookie.getValue());
            w.write("您上次访问的时间:"+ new Date(lastTime).toLocaleString());
        }

        //4.记录当前访问时间,并且该信息存入cookie中
        Cookie c = new Cookie("record",System.currentTimeMillis()+"");
        //设置cookie的有效期是 1 小时
        c.setMaxAge(60*60);
        response.addCookie(c);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

Cookie案例 : 浏览记录

  • 核心代码1:记录商品浏览记录
/**
 * 记录商品浏览记录,只展示3个商品
 */
public class CategoryServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取当前访问商品的id
        String id = request.getParameter("id");

        Cookie c = CookieUtils.getCookieByName("ids",request.getCookies());

        //判断该 cookie 是否为空
        String ids="";
        if(c == null){
            //若为空,说明之前没有访问记录
            //将当前商品的id放入ids中
            ids = id;
        }else{
            //若不为空,获取值。也就是之前浏览的商品编号,使用 "-"进行连接
            ids = c.getValue();

            //将 ids 通过"-"进行分割,然后存入list中,方便后续的操作
            String[] categoryIds = ids.split("-");
            LinkedList<String> categories = new LinkedList<>();
            if(categories != null){
                for(String categoryId : categoryIds){
                    categories.add(categoryId);
                }
            }
            //判断之前记录中有无该商品
            if(categories.contains(id)){
                //若有,删除原来的id,将当前的id放入前面
                categories.remove(id);
            }else{
                // 若没有
                // 继续判断长度是否>=3
                // 若>=3,移除最后一个,将当前的id放入最前面
                // 若<3,直接将当前的id放入最前面.
                if(categories.size() >= 3){
                    categories.removeLast();
                }
            }
            //不管如何,id都是最新浏览的,直接加入到前面
            categories.addFirst(id);

            ids="";
            for(String categoryId : categories){
                ids += (categoryId + "-");
            }
            ids = ids.substring(0,ids.length()-1);
        }

        //创建cookie
        c=new  Cookie("ids",ids);
        //设置访问路径
        c.setPath(request.getContextPath()+"/");
        //设置存活时间
        c.setMaxAge(60);

        //写回浏览器
        response.addCookie(c);

        //跳转到指定的商品页面上
        response.sendRedirect(request.getContextPath()+"/category_info"+id+".htm");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
  • 显示浏览记录
<ul style="list-style: none;">
    <%
        //获取指定名称的cookie ids
        Cookie c= CookieUtils.getCookieByName("ids", request.getCookies());

        //判断ids是否为空
        if(c==null){
    %>
    <h2>暂无浏览记录</h2>
    <%
    }else{//ids=3-2-1
        String[] arr=c.getValue().split("-");
        for(String id:arr){
    %>
    <li style="width: 150px;height: 216;float: left;margin: 0 8px 0 0;padding: 0 18px 15px;text-align: center;"><img src="category/0<%=(Integer.parseInt(id)-1) %>.jpg" width="130px" height="130px" /></li>
    <%
            }
        }
    %>
</ul>
  • 核心代码2:清空浏览记录
/**
 * 清空浏览记录
 */
public class ClearServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie c = new Cookie("ids","");

        //cookie的路径与 CategoryServlet中的cookie中的路径要相同
        c.setPath(request.getContextPath()+"/");
        //直接将cookie设置成无效
        c.setMaxAge(0);
        response.addCookie(c);

        //重定向
        response.sendRedirect(request.getContextPath()+"/category_list.jsp");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
  • 注意:
  1. cookie是不能跨浏览器的

  2. cookie不支持中文,需要编码

推荐阅读:

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值