Cookie是一种在客户端保存信息的技术,通过Cookie可以向客户端写入和读取消息。还可以通过编码的方式向Cookie中写入复杂数据,如被序列化的对象实例、图像等。
一、什么是Cookie
在浏览网页的时候可能会注意到这样的现象,如在打开某个登录网页时,第一次打开时,用户名文本框是空的。当输入一个用户名并成功登录后,第二次打开这个登录网页时,第一次输入的用户名会被自动填入这个用户名文本框,就算重启计算机后,仍然如此。其实,这就是Cookie所起的作用。由于HTTP协议是无状态的,因此他是不可能保存这个歌用户名的。那么这种可能就是在第一次登录后,将这个用户名保存在了客户端硬盘的某个地方。当再次访问这个页面的时候,浏览器会根据这个保存在客户端硬盘上的用户名或标识知道这个用户曾经访问过这个页面,并对这个用户做进一步的处理。这个被保存的用户名或用户标识就被称为一个Cookie。Cookie是在浏览器访问某个Web资源时,由Web服务器在HTTP响应消息头中通过Set-Cookie字段发送给浏览器的一组消息。
浏览器会根据Set-Cookie字段中的Cookie数据决定是否保存这些Cookie。当浏览器下一次访问这个Web资源时,会自动读取这些被保存的Cookie,并加到HTTP请求消息头的Cookie字段中,Web服务器会根据Cookie字段的内容作出相应的处理。如上述的用户名信息将使用Cookie字段发送到Web服务器,然后Web服务器会获得这个用户名,并做进一步处理。
一个Cookie值表示一个key-value键值对,这个key-value对由Cookie名和Cookie值组成。Web服务器可以给一个Web浏览器发送多个Cookie,但每个Cookie的大小一般被限制为4KB。在Servlet API 中,使用java.servlet.http.Cookie类来封装一个Cookie消息,在HttpServletResponse接口中定义了一个addCookie()方法来向浏览器发送Cookie对象,在HttpServletRequest接口中定义了一个getCookies()方法来读取浏览器传递过来的Cookie消息。Cookie类中定义了生成和获取Cookie消息的各个属性的方法。Cookie类只有一个构造方法:
public Cookie(String name,String value)
其中name表示Cookie名(在name参数值中不能包含任何空格字符、逗号、分号,并且不能以$字符开头),value表示Cookie 的值。Cookie类的其它常用方法:
- getName():该方法返回Cookie 的名称。
- setValue()和getValue() :这两个方法分别用于设置和获取Cookie的值。
- setMaxAge()和getMaxAge() :这两个方法分别用于设置和获取Cookie在客户端的有效时间(以秒为单位)。如果设置为0,表示当Cookie消息发送到客户端浏览器时被立即删除。如果设置为负数,表示浏览器并不会把这个Cookie保存在硬盘上,这种Cookie被称为临时Cookie(保存在硬盘上的Cookie被称为永久Cookie),它们只存在于当前浏览器的进程中,当浏览器关闭后,Cookie自动失效。对于IE浏览器,不同的窗口不能共享临时Cookie,但按Ctrl+N快捷键或使用JavaScript的window.open语句打开的窗口由于和它们的父窗口属于同一个浏览器进程,因此它们可以共享临时Cookie。而在FireFox中,所有的进程和标签页都可以共享临时Cookie。
- setPath和getPath方法:这两个方法分别用于设置和获取当前Cookie的有效Web路径。如果在创建某个Cookie时为设置它的path属性,那么该Cookie只对当前访问的Servlet所在的Web路径及其子路径有效。如果想使Cookie对整个Web站点中的所有可访问的路径都有效,需要将path属性值设置为"/" 。
- setComment和getComment方法:这两个方法分别用于设置和获取当前Cookie 的注释部分。
- setVersion和getVersion方法:这两个方法分别用于设置和获取当前Cookie的协议版本。
- setSecure和getSecure方法:这两个方法分别用于设置和获取当前Cookie是否只能使用安全的协议传输Cookie。
下面演示如何在Servlet中使用Cookie。其中SaveCookie类负责向客户端浏览器写入3种Cookie:永久Cookie、临时Cookie 和有效时间为0 的Cookie:
import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SaveCookie extends HttpServlet { /** * */ private static final long serialVersionUID = -8265745579634360083L; protected void service(HttpServletRequest request ,HttpServletResponse response) throws ServletException , IOException{ response.setContentType("text/html; charset=UTF-8 "); //PrintWriter out = response.getWriter() ; Cookie tempCookie = new Cookie("temp","87654321"); //创建临时Cookie,不设置setMaxAge属性 response.addCookie(tempCookie); //添加临时Cookie对象 //创建有效时间为0 的Cookie Cookie cookie = new Cookie("cookie" , "6666") ; cookie.setMaxAge(0); response.addCookie(cookie); //获取请求参数User的值 String user = request.getParameter("user") ; if(user!=null){ Cookie userCookie = new Cookie("user" , user) ; userCookie.setMaxAge(3600); userCookie.setPath("/"); // 这个Cookie对站点中所有目录下的访问路径都有效 response.addCookie(userCookie); } // response.sendRedirect("ReadCookie"); RequestDispatcher readCookie = getServletContext().getRequestDispatcher("/servlet/ReadCookie") ; readCookie.include(request, response); } }
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ReadCookie extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; protected Cookie getCookieValue(Cookie[] cookies , String name){ if(cookies!=null){ for(Cookie c :cookies){ if(c.getName().equals(name)){ return c ; } } } return null ; } public void service(HttpServletRequest request ,HttpServletResponse response) throws ServletException , IOException{ response.setContentType("text/html ;charset=UTF-8"); PrintWriter out = response.getWriter() ; Cookie tempCookie =getCookieValue(request.getCookies(),"temp"); if(tempCookie != null){ out.println("临时Cookie值:"+tempCookie.getValue()+"<br>"); }else { out.print("临时Cookie未设置!<br>"); } Cookie cookie = getCookieValue(request.getCookies(),"cookie"); if(cookie!=null){ out.println("cookie:"+cookie.getValue()+"<br>"); }else { out.println("cookie已经被删除!<br>"); } Cookie userCookie = getCookieValue(request.getCookies(),"user"); if(userCookie !=null){ out.println("user:"+userCookie.getValue()); }else { out.println("user未设置!"); } } }
解决Cookie乱码问题,即使在开头设置了request和response的中文编码格式,直接在Cookie的参数值中保存中文字符会出现乱码或者运行错误,需要使用java.net.URLEncoder类的encode()方法对有中文参数的变量接受时进行编码处理,再放入创建的Cookie对象中作为参数值:
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html ; charset=utf-8");
String username =URLEncoder.encode(request.getParameter("cname"), "utf-8") ; //username中有中文!
//String username = request.getParameter("cname") ;
String password = request.getParameter("psd") ;
String rememberme = request.getParameter("rememberme");
System.out.println(username);
System.out.println(password);
System.out.println(rememberme);
if(username!=null&&username.trim().length()>0&&password!=null&&password.trim().length()>0){
if(rememberme!=null&&rememberme.trim().length()>0){
Cookie[] ck = request.getCookies();
for(Cookie c: ck){
System.out.println(c.getName());
}
Cookie c_username = new Cookie("username",username);
Cookie c_password = new Cookie("password",password) ;
c_username.setMaxAge(3600);
c_password.setMaxAge(3600);
response.addCookie(c_username);
response.addCookie(c_password);
System.out.println("Cookie已经添加!");
}
然后接收Cookie后在使用Cookie里的参数值前,需要将有中文的那个参数值再解码,使用java.net.URLDecoder类的decode()方法解码,然后再使用这个参数值,便可正确显示。
<body>
<%
String username = "" ;
String password = "" ;
Cookie[] cs = request.getCookies();
if(cs!=null){
//out.print("Cookie已经存在! ");
for(Cookie c: cs){
if("username".equals(c.getName())){
username = c.getValue();
}
if("password".equals(c.getName())){
password = c.getValue();
}
}
}
%>
<form action="LoginServlet" method="post">
<table>
<tr><td>用户名:</td><td><input type="text" name="cname" value="<%=URLDecoder.decode(username, "utf-8")%>"/></td></tr>
<tr><td>密码:</td><td><input type="password" name="psd" value="<%=password%>"/></td></tr>
<tr><td colspan="2"><input type="checkbox" name="rememberme" value="do"/></td></tr>
<tr><td><input type="submit" value="提交"/></td></tr>
</table>
</form>
</body>
</html>