Cookie

Cookie简介

  Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。定义于 RFC2109 和 2965 中的都已废弃,最新取代的规范是 RFC6265 。(可以叫做浏览器缓存)

  基于 Internet的各种服务系统应运而生,建立商业站点或者功能比较完善的个人站点,常常需要记录访问者的一些信息;论坛作为 Internet发展的产物之一,在 Internet 中发挥着越来越重要的作用,是用户获取、交流、传递信息的主要场所之一,论坛常常也需要记录访问者的一些基本信息(如身份识别号码、密码、用户在 Web 站点购物的方式或用户访问该站点的次数)。目前公认的是,通过 Cookie 和 Session 技术来实现记录访问者的一些基本信息 。

  Cookie 在计算机中是个存储在浏览器目录中的文本文件,当浏览器运行时,存储在 RAM 中发挥作用 (此种 Cookies 称作 Session Cookies),一旦用户从该网站或服务器退出,Cookie 可存储在用户本地的硬盘上 (此种 Cookies 称作 Persistent Cookies) 。

  通常情况下,当用户结束浏览器会话时,系统将终止所有的 Cookie。当 Web 服务器创建了Cookies 后,只要在其有效期内,当用户访问同一个 Web 服务器时,浏览器首先要检查本地的Cookies,并将其原样发送给 Web 服务器。这种状态信息称作“Persistent Client State HTTP Cookie” ,简称为 Cookies。

Cookie的特点

  • 在同一个页面中设置 Cookie,实际上是按从后往前的顺序进行的。如果要先删除一个 Cookie,再写入一个 Cookie,则必须先写写入语句,再写删除语句,否则会出现错误 。

  • Cookie是面向路径的。缺省路径 (path) 属性时,Web 服务器页会自动传递当前路径给浏览器,指定路径强制服务器使用设置的路径。在一个目录页面里设置的 Cookie 在另一个目录的页面里是看不到的 。

  • Cookie 必须在 HTML 文件的内容输出之前设置;不同的浏览器 (Netscape Navigator、Internet Explorer) 对 Cookie 的处理不一致,使用时一定要考虑;客户端用户如果设置禁止 Cookie,则 Cookie 不能建立。 并且在客户端,一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的 Cookie 总数不能超过 20 个 。

Cookie源码

package javax.servlet.http;

import java.text.MessageFormat;
import java.util.ResourceBundle;

public class Cookie implements Cloneable {
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
    private String name;
    private String value;
    private String comment;
    private String domain;
    private int maxAge = -1;
    private String path;
    private boolean secure;
    private int version = 0;
    private static final String tspecials = ",; ";

    public Cookie(String name, String value) {
        if (this.isToken(name) && !name.equalsIgnoreCase("Comment") && !name.equalsIgnoreCase("Discard") && !name.equalsIgnoreCase("Domain") && !name.equalsIgnoreCase("Expires") && !name.equalsIgnoreCase("Max-Age") && !name.equalsIgnoreCase("Path") && !name.equalsIgnoreCase("Secure") && !name.equalsIgnoreCase("Version") && !name.startsWith("$")) {
            this.name = name;
            this.value = value;
        } else {
            String errMsg = lStrings.getString("err.cookie_name_is_token");
            Object[] errArgs = new Object[]{name};
            errMsg = MessageFormat.format(errMsg, errArgs);
            throw new IllegalArgumentException(errMsg);
        }
    }

    public void setComment(String purpose) {
        this.comment = purpose;
    }

    public String getComment() {
        return this.comment;
    }

    public void setDomain(String pattern) {
        this.domain = pattern.toLowerCase();
    }

    public String getDomain() {
        return this.domain;
    }

    public void setMaxAge(int expiry) {
        this.maxAge = expiry;
    }

    public int getMaxAge() {
        return this.maxAge;
    }

    public void setPath(String uri) {
        this.path = uri;
    }

    public String getPath() {
        return this.path;
    }

    public void setSecure(boolean flag) {
        this.secure = flag;
    }

    public boolean getSecure() {
        return this.secure;
    }

    public String getName() {
        return this.name;
    }

    public void setValue(String newValue) {
        this.value = newValue;
    }

    public String getValue() {
        return this.value;
    }

    public int getVersion() {
        return this.version;
    }

    public void setVersion(int v) {
        this.version = v;
    }

    private boolean isToken(String value) {
        int len = value.length();

        for(int i = 0; i < len; ++i) {
            char c = value.charAt(i);
            if (c < ' ' || c >= 127 || ",; ".indexOf(c) != -1) {
                return false;
            }
        }

        return true;
    }

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException var2) {
            throw new RuntimeException(var2.getMessage());
        }
    }
}

Cookie的使用

  示例代码如下:

        Cookie cookie = new Cookie("username","password"); // 新建Cookie
        cookie.setMaxAge(Integer.MAX_VALUE); // 设置生命周期为MAX_VALUE
        response.addCookie(cookie); // 输出到客户端

Cookie的修改

  在这里离需要注意的是Cookie是只有添加方法,没有修改方法,因而我们要想完成修改操作,那么我们只有再次生成一次了,用后来的数据覆盖前面的数据(前提是key值必须相同)。

Cookie的删除

  在Cookie中,同样也没有删除方法,而我们要想实现删除Cookie的操作,那么我们需要将Cookie的maxAge参数置为负数,比如说源码中的初始值就是-1,所以说我们也可以参考这个,如果要想将Cookie删除,我们也可以将其maxAge参数置为-1。

Cookie的有效期

  maxAge是Cookie的有效期,默认的情况下,Cookie的初始值是-1,其意思就是当浏览器退出时,清除Cookie。如果我们要想让Cookie保存一段时间,比如说是一周,其设置为7*24*60*60(秒)。

Cookie的注意事项

  修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。

Cookie的域名

  Cookie是不可跨域名的。域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的Cookie。

  正常情况下,同一个一级域名下的两个二级域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有helloweenvsfei.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数为“.helloweenvsfei.com”。

Cookie的路径

  Cookie是不允许跨路径(ContextPath)访问的,不同的路径下的Cookie即便是name和value相同,仍被视为不同的Cookie,因而不能随便完成Cookie的修改、删除操作。比如说/aa路径下访问/cc路径下的Cookie,此时是注定会失败的。但是Cookie允许本路径下的子路径访问本路径,也就是说当/aa/bb访问/aa路径下的Cookie,此时是能够正常访问的。而要使所有的路径下都能够访问Cookie,我们得将Cookie的path属性更改为/

Cookie的校验

  Cookie要想实现秒登录功能,其主要还是通过Cookie的校验。Cookie的校验的校验主要有两种方式:其一是根据密码进行校验;其二是根据最后一次的Cookie时间进行校验。

根据密码校验

  根据密码校验,顾名思义,就是先根据Cookie中的用户名在数据库中查找,一旦找到该信息,立即将其取出,然后再与Cookie中的密码进行比较,如果一致,则验证通过。示例代码如下:

/**
     * 根据cookie中的密码进行校验
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/password")
    public String password(HttpServletRequest request, HttpServletResponse response){
        Cookie[] cookies = request.getCookies();
        if(cookies.length > 0){
            for(int i = 0;i < cookies.length;i ++){
                Cookie cookie = cookies[i];
                log.info("cookie的key为:{},value为:{}",cookie.getName(),cookie.getValue());
                //验证登录信息
                if(validParamPassword(cookie)){
                    return "success";
                }
            }
        }
        return "error";
    }

    /**
     * 根据cookie中的密码进行校验
     * @param cookie
     * @return
     */
    private Boolean validParamPassword(Cookie cookie){
        if(cookie.getName().equals("zhangsan") && cookie.getValue().equals(MD5Util.encrypt("zhangsan123"))){
            return true;
        }
        if(cookie.getName().equals("lisi") && cookie.getValue().equals(MD5Util.encrypt("lisi123"))){
            return true;
        }
        return false;
    }

根据最后一次Cookie时间进行校验

  该方法的思路是每次服务器向用户颁发Cookie时都在数据库中更新一次Cookie颁发时间,这样如果下次访问,服务器可通过Cookie中的用户名在数据库中查出相应的信息,然后再与客户端的颁发时间进行比对,如果颁发时间一致,则验证通过,该方法的另一个优点是避免了用户密码存储在用户本地,因而更加的安全可靠。示例代码如下:

/**
     * 根据cookie中的存储时间进行校验
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/cookiedTime")
    public String cookiedTime(HttpServletRequest request, HttpServletResponse response){
        Cookie[] cookies = request.getCookies();
        if(cookies.length > 0){
            for(int i = 0;i < cookies.length;i ++){
                Cookie cookie = cookies[i];
                log.info("cookie的key为:{},value为:{}。",cookie.getName(),cookie.getValue());
                //验证登录信息
                if(validParamTime(cookie)){
                    return "success";
                }
            }
        }
        return "error";
    }

    /**
     * 根据cookie存储时间进行校验
     * @param cookie
     * @return
     */
    private Boolean validParamTime(Cookie cookie){
        Test test = cookieService.selectByName(cookie.getName());
        if(test != null){
            if(String.valueOf(test.getUpdatetime().getTime()).equals(cookie.getValue())){
                return true;
            }
        }
        return false;
    }

参考文章:
   Cookie
  理解Cookie和Session机制
源码:
  cookie-demo1


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值