5.3.3 读写Cookie信息与Cookie的中文问题

优质
小牛编辑
135浏览
2023-12-01

在一些Web应用程序中需要在客户端保存一些信息,如用户名等,以使在下次访问同一个Web程序时可以根据这些信息为用户提供方便,或作为其他的用途。这些信息是由一个key-value对组成。每一对这样的信息被称为一个Cookie。如有一些登录程序在下一次访问时,会自动将用户名显示在用户名文本框中,这就是通过Cookie实现的。

下面的例子演示了如何在Servlet中读、写Cookie信息。

例子 : 读写Cookie信息(包括英文和中文信息)

1. 实例说明

本程序通过WriteCookie和ReadCookie类来分别设置和读取Cookie信息。其中WriteCookie类设置了不同类型的Cookie,包括临时Cookie和永久Cookie。ReadCookie类在不同的情况下读取了这些Cookie信息,读者可以从中了解到不同类型Cookie的区别。

2. 编写WriteCookie类

package chapter5;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class WriteCookie extends HttpServlet
{
    public void service(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException
    {
        // 临时Cookie
        Cookie tempCookie = new Cookie("temp", "temporary cookie");
        tempCookie.setMaxAge(-1); // 设为临时Cookie,-1是MaxAge的默认值
        response.addCookie(tempCookie);       
        // 这个cookie不起作用
        Cookie cookie = new Cookie("cookie", "deleted");
    // Cookie的有效时间设为0,浏览器接收以Cookie后立即被删除
        cookie.setMaxAge(0);
        response.addCookie(cookie);
        //  永久Cookie
        //  由于永久Cookie的值是中文,所以需要对其进行编码             
        String chinese = java.net.URLEncoder.encode("将Cookie保存到硬盘上", "UTF-8");
        Cookie persistentCookie = new Cookie("pCookie", chinese);
        persistentCookie.setMaxAge(60 * 60 * 24);       // 有效时间为1天
        // 设置有效路径,设为“/”表示这个Cookie在整个站点都是有效的
        persistentCookie.setPath("/"); 
        response.addCookie(persistentCookie);
    }
}

上面的代码分别建立了三种Cookie:临时Cookie、有效时间为0的Cookie和永久Cookie。其中临时Cookie只在当前的浏览器窗口有效。而将Cookie的有效时间设为0,则该Cookie不会起到任何作用,因为这种Cookie一到浏览器就会被立即删除。浏览器会将永久Cookie保存在本地硬盘上,对于这种Cookie,即使是在新的浏览器窗口,只要在Cookie的有效期内,该Cookie就会永远有效。

从上面的描述可以看出,Cookie的不同类型是根据有效时间的取值范围确定的,如下所示:

l Cookie有效时间 < 0:临时Cookie,只在当前浏览器窗口以及和该窗口处于同一个进程的窗口中有效。

2  Cookie有效时间 = 0:该Cookie会立即被浏览器删除。

3  Cookie有效时间 > 0:永久Cookie,在Cookie有效时间内有效。

3. 编写ReadCookie类

package chapter5;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ReadCookie extends HttpServlet
{
    // 通过一个Cookie名获得Cookie对象,未找到指定名的Cookie对象,返回null
    private 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 ,getCookies方法获得一个保存了请求消息头中所有Cookie的数组
        Cookie tempCookie = getCookieValue(request.getCookies(), "temp");
        if (tempCookie != null)
            out.println("临时Cookie值:" + tempCookie.getValue() + "<br/>");
        else
            out.println("临时Cookie值:null</br>");
        // 这个Cookie永远不可能获得,因为它的MaxAge为0
        Cookie cookie = getCookieValue(request.getCookies(), "cookie");
        if (cookie != null)
            out.println("cookie:" + cookie.getValue() + "<br/>");
        else
            out.println("cookie:null</br>");
        // 获得永久Cookie
        Cookie persistentCookie = getCookieValue(request.getCookies(), "pCookie");
        if (persistentCookie != null)
            //  对永久Cookie中保存的中文信息进行解码
            out.println("persistentCookie:" + java.net.URLDecoder.decode(persistentCookie.getValue(), "UTF-8"));
        else
            out.println("persistentCookie:null!");
    }
}

在上面的代码中分别读取了在WriteCookie类中设置的三个Cookie。由于HttpServletRequest接口中未提供通过Cookie名返回特定Cookie对象的方法,因此,在ReadCookie类中增加了一个getCookieValue方法,用于返回指定Cookie名的Cookie对象。

4. 配置WriteCookie和ReadCookie类

这两个类的配置代码如下:

<!--  配置WriterCookie  -->

<servlet>
    <servlet-name>WriteCookie</servlet-name>
    <servlet-class>chapter5.WriteCookie</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>WriteCookie</servlet-name>
    <url-pattern>/WriteCookie</url-pattern>
</servlet-mapping>

<!--  配置ReadCookie  -->

<servlet>
    <servlet-name>ReadCookie</servlet-name>
    <servlet-class>chapter5.ReadCookie</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>ReadCookie</servlet-name>
    <url-pattern>/ReadCookie</url-pattern>
</servlet-mapping>

5. 在同一个浏览器窗口中测试

在浏览器地址栏中依次输入如下两个URL:

http://localhost:8080/demo/WriteCookie

http://localhost:8080/demo/ReadCookie

浏览器中显示的结果如图5.16所示。

16

图5.16 在同一个浏览器窗口读取Cookie值

实际上,在访问WriteCookie时,addCookie方法向HTTP响应消息头添加了如下的三个Set-Cookie字段:

Set-Cookie: temp="temporary cookie"

Set-Cookie: cookie=deleted; Expires=Thu, 01-Jan-1970 00:00:10 GMT

Set-Cookie:pCookie=%E5%B0%86Cookie%E4%BF%9D%E5%AD%98%E5%88%B0%E7%A1%AC%E7%9B%98%E4%B8%8A; Expires=Tue, 24-Jun-2008 14:43:23 GMT; Path=/

6. 在不同的浏览器窗口中测试

打开一个新的浏览器窗口,在浏览器地址栏中输入如下的URL:

http://localhost:8080/demo/ ReadCookie

浏览器中显示的结果如图5.17所示。

17

图5.17 在不同的浏览器窗口读取Cookie值

 从上面的测试结果可以看出,在新的浏览器窗口中,并不存在这个临时Cookie,因此,临时Cookie的值为null。

7. 程序总结

在WriterCookie类中使用了setPath方法设置的Cookie有效路径。假设使用setPath设置的路径为“/path”,如果通过localhost访问Web资源。要想该Cookie有效,访问Web资源的URL的前半部分必须是“http://localhost:8080/path”。如下面的URL所指的Servlet可以访问这个Cookie:

http://localhost:8080/path/servlet/MyServlet

实际上,这个路径就相当于上下文路径,如果只想让某个Cookie在当前Web应用程序中有效,可以使用HttpServletRequest接口的getContextPath方法返回值来设置这个Cookie的有效路径。

在使用Cookie时,还有一点需要注意,由于Cookie只支持ISO-8859-1编码格式的字符,因此,不能直接向Cookie中写入中文,如果要让Cookie支持中文,需要将中文字符编码。如Base64编码、URL格式的UTF-8编码。在本例中采用的是URL格式的UTF-8编码。