1. 为什么会有cookie机制?
会话是通过http协议进行通信的,但http协议是一种无状态协议(即当浏览器向服务器发送一次请求,服务器响应请求之后通信便结束),若同一个浏览器在一个网站上面请求多次本网站的其它资源,则每次都需建立浏览器与服务器的连接。这样就意味着服务器无法从连接上跟踪服务器。
Cookie就是这样的一种机制,它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
2. 什么是cookie?
其实,简单来说,cookie就是一段小的文本信息。当用户通过(无状态)http协议访问服务器时,服务器都会给用户一个cookie,来记录用户信息。
客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
注意:cookie需要浏览器支持,不同浏览器使用不同方式保存cookie。
3. cookie怎么用?
3.1 记录用户访问次数
Java把cookie封装成一个javax.servlet.http.Cookie类,每个cookie都是该类的对象。服务器通过操作cookie类对象来对每个客户端浏览器cookie对象进行操作。主要操作有:通过request.getCookie()来得到客户端的所有cookie对象信息(以cookie[ ]数组形式返回);通过response.addCookie(Cookie cookie)对客户端cookie类对象进行设置修改。
cookie对象使用key-value(键值对)的形式保存用户状态,一个Cookie对象保存一个属性对,一个request或者response同时使用多个Cookie。因为Cookie类位于包javax.servlet.http.*下面,所以JSP中不需要import该类。
3.2 cookie的不可跨域名性
很多网站的服务器都会使用cookie,Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。
3.3 Unicode编码:中文字符
中英文的字符不同,中文属于Unicode字符,在内存中占4个字符;而英文属于ASCII字符,占2个字节。cookie中使用Unicode字符时,需要进行Unicode编码,否则会乱码。一般中文采用UTF-8编码即可。
cookie不仅可以使用ASCII字符和Unicode字符,还可以使用二进制数据。例如在Cookie中使用数字证书,提供安全度。使用二进制数据(如二进制图片)时也需要进行编码。
3.4 Cookie所有属性
cookie常用属性如下表
属性名 | 描述 |
String name | 该cookie名称,一旦创建便不可变 |
Object value | 该cookie的值,如果是Unicode字符,则需要Unicode编码 |
int maxAge | 该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1 |
boolean secure | 该cookie是否使用安全协议进行传输。如HTTPS、SSL等,在网络上传输数据之前需先加密。默认为false。 |
String path | 该cookie的传输路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/” |
String domain | 可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.” |
String comment | 该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明 |
Int version | 该cookie的版本号 |
3.5 cookie的有效期
Cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。Cookie中通过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。
如果maxAge属性为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效。
Cookie cookie = new Cookie("username","helloweenvsfei"); // 新建Cookie
cookie.setMaxAge(Integer.MAX_VALUE); // 设置生命周期为MAX_VALUE
response.addCookie(cookie); // 输出到客户端
失效的Cookie会被浏览器从Cookie文件或者内存中删除,例如:
Cookie cookie = new Cookie("username","helloweenvsfei"); // 新建Cookie
cookie.setMaxAge(0); // 设置生命周期为0,不能为负数
response.addCookie(cookie); // 必须执行这一句
response对象提供的Cookie操作方法只有一个添加操作add(Cookie cookie)。
要想修改Cookie只能使用一个同名的Cookie来覆盖原来的Cookie,达到修改的目的。删除时只需要把maxAge修改为0即可。
3.6 cookie的修改、删除
Cookie并不提供修改、删除操作。如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。
如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数代表其他的意义。读者可以通过上例的程序进行验证,设置不同的属性。
注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
3.7 cookie的域名
cookie是不可夸域名的。正常情况下,同一个域名下的两个二级域名如www.baidu.com和image.baidu.com是不能交互使用cookie的,因为这两个域名并不严格相同。如果想要baidu.com下的所有二级域名都使用一个cookie,需对该cookie进行设置,例如:
Cookie cookie = new Cookie("username","20160526");//新建cookie
cookie.setDomain(".baidu.com"); //设置域名
cookie.setPath("/"); //设置路径
cookie.setMaxAge(integer.Max_Value); //设置有效时间
response.addCookie(cookie); //输出到客户端
注意:domain参数必须以点(".")开始。另外,name相同但domain不同的两个Cookie是两个不同的Cookie。如果想要两个域名完全不同的网站共有Cookie,可以生成两个Cookie,domain属性分别为两个域名,输出到客户端。
3.8 cookie的安全性
HTTP协议不仅是无状态的,还是不安全的。可以设置cookie的secure属性为true。浏览器会在HTTPS和SSL等安全协议中传输此类cookie
cookie.setSecure(true);//设置安全性
提示:secure属性并不能对Cookie内容加密,因而不能保证绝对的安全性。如果需要高安全性,需要在程序中对Cookie内容加密、解密,以防泄密。
4. cookie的缺点
- cookie数量和长度的限制,每个domain最多只有20条cookie,每个cookie长度不能超过4K,否则会被截掉
- 安全性问题。如果cookie被人拦截,那就可以取得所有session信息。即使加密也没用,因为并不需要知道cookie本身的意义,只需要按照原样转发就行了。
- 有些状态不可能保存在客户端。例如:为了防止重复提交表单,我们需要在服务器端设计一个计数器,如果把计数器放在客户端将不起作用。