引言
由于 Http 是一种无状态的协议,服务器单从网络连接上无从知道客户身份。
会话跟踪是 Web 程序中常用的技术,用来跟踪用户的整个会话。常用会话跟踪技术是 Cookie 与
Session。
Cookie是什么?
Cookie 实际上是存储在客户端上的文本信息,并保留了各种跟踪的信息。
Cookie工作步骤:
(1)客户端请求服务器,如果服务器需要记录该用户的状态,就是用 response 向客户端浏览器颁发一个 Cookie。
(2)客户端浏览器会把 Cookie 保存下来。
(3)当浏览器再请求该网站时,浏览器把该请求的网址连同 Cookie 一同提交给服务器。服务器检查该 Cookie,以此来辨认用户状态。
注:Cookie功能需要浏览器的支持,如果浏览器不支持Cookie或者Cookie禁用了,Cookie功能就会失效。
Java中把Cookie封装成了javax.servlet.http.Cookie类。
Cookie剖析
Cookies 通常设置在 HTTP 头信息中(虽然 JavaScript 也可以直接在浏览器上设置一个 Cookie)。设置 Cookie 的 Servlet 会发送如下的头信息:
HTTP/1.1 200 OK Date: Fri, 04 Feb 2000 21:03:38 GMT Server: Apache/1.3.9 (UNIX) PHP/4.0b3 Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT; path=/; domain=w3cschool.cc Connection: close Content-Type: text/html |
正如您所看到的,Set-Cookie 头包含了一个名称值对、一个 GMT 日期、一个路径和一个域。名称和值会被 URL 编码。expires
字段是一个指令,告诉浏览器在给定的时间和日期之后"忘记"该 Cookie。
如果浏览器被配置为存储 Cookies,它将会保留此信息直到到期日期。如果用户的浏览器指向任何匹配该 Cookie 的路径和域的页面,它会重新发送 Cookie 到服务器。浏览器的头信息可能如下所示:
GET / HTTP/1.0 Connection: Keep-Alive User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc) Host: zink.demon.co.uk:1126 Accept: image/gif, */* Accept-Encoding: gzip Accept-Language: en Accept-Charset: Cookie: name=xyz |
Cookie类中的方法
方法 |
功能 |
public void setDomain(String pattern) |
该方法设置 cookie 适用的域。 |
public String getDomain() |
该方法获取 cookie 适用的域。 |
public void setMaxAge(int expiry) |
该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。 |
public int getMaxAge() |
该方法返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示 cookie 将持续下去,直到浏览器关闭。 |
public String getName() |
该方法返回 cookie 的名称。名称在创建后不能改变。 |
public void setValue(String newValue) |
该方法设置与 cookie 关联的值。 |
public String getValue() |
该方法获取与 cookie 关联的值。 |
public void setPath(String uri) |
该方法设置 cookie 适用的路径。如果您不指定路径,与当前页面相同目录下的(包括子目录下的)所有 URL 都会返回 cookie。 |
public String getPath() |
该方法获取 cookie 适用的路径。 |
public void setSecure(boolean flag) |
该方法设置布尔值,向浏览器指示,只会在HTTPS和SSL等安全协议中传输此类Cookie。 |
public void setComment(String purpose) |
该方法规定了描述 cookie 目的的注释。该注释在浏览器向用户呈现 cookie 时非常有用。 |
public String getComment() |
该方法返回了描述 cookie 目的的注释,如果 cookie 没有注释则返回 null。 |
Cookie的有效期
Cookie的maxAge决定着Cookie的有效期,单位为秒。
如果maxAge为0,则表示删除该Cookie;如果为负数,表示该Cookie仅在本浏览器中以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。
Cookie中提供getMaxAge()和setMaxAge(int expiry)方法来读写maxAge属性。
Cookie的域名
Cookie是不可以跨域名的。域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的Cookie。
正常情况下,同一个一级域名的两个二级域名之间也不能互相使用Cookie。如果想让某域名下的子域名也可以使用该Cookie,需要设置Cookie的domain参数。
Java中使用setDomain(String domain)和getDomain()方法来设置、获取domain。
Cookie的路径
Path属性决定允许访问Cookie的路径。
Java中使用setPath(String uri)和getPath()方法来设置、获取path。
Cookie的安全属性
HTTP协议不仅是无状态的,而且是不安全的。
使用HTTP协议的数据不经过任何加密就直接在网络上传播,有被截获的可能。如果不希望Cookie在HTTP等非安全协议中传输,可以设置Cookie的secure属性为true。浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie。
Java中使用setSecure(boolean flag)和getSecure ()方法来设置、获取Secure。
实例
添加Cookie
通过 Servlet 添加
Cookies 包括三个步骤:
(1)创建一个
Cookie 对象:您可以调用带有 cookie 名称和
cookie 值的
Cookie 构造函数,cookie 名称和
cookie 值都是字符串。
(2)设置最大生存周期:您可以使用 setMaxAge 方法来指定 cookie 能够保持有效的时间(以秒为单位)。
(3)发送
Cookie 到
HTTP 响应头:您可以使用 response.addCookie 来添加
HTTP 响应头中的 Cookies。
AddCookieDemo.java
package notes.javaee.servlet.cookie; // 导入必需的 java 库 import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; // 扩展 HttpServlet 类 @WebServlet("/servlet/cookie/addCookieDemo") public class AddCookieDemo extends HttpServlet { private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, Cookie cookieName = new Cookie("name", request.getParameter("name")); Cookie cookieAge = new Cookie("age", request.getParameter("age")); // 为两个Cookie设置有效期 cookieName.setMaxAge(30); cookieAge.setMaxAge(30); // 在响应头中添加两个 Cookies response.addCookie(cookieName); response.addCookie(cookieAge); // 设置响应内容类型 response.setContentType("text/html"); response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); String title = "设置 Cookies 实例"; String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n"; out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n" + "<h1 align=\"center\">" + title + "</h1>\n" + "<ul>\n" + " <li><b>名字</b>:" + request.getParameter("name") + "\n" + " <li><b>年龄</b>:" + request.getParameter("age") + "\n" + "</ul>\n" + "</body></html>"); } } |
ShowCookieDemo.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>显示Cookie</title> </head> <body> <form action="/ServletNotes/servlet/cookie/showCookieDemo"method="GET"> 名字:<input type="text" name="name"> <br /> 年龄:<input type="text" name="age"/> <input type="submit"value="提交" /> </form> </body> </html> |
访问http://localhost:8080/ServletNotes/ShowCookieDemo.html,提交输入文本后,可以看到cookie内容。
显示Cookie
要读取 Cookies,您需要通过调用 HttpServletRequest的getCookies()方法创建一个 javax.servlet.http.Cookie对象的数组。然后循环遍历数组,并使用 getName() 和 getValue() 方法来访问每个 cookie 和关联的值。
ReadCookies.java
package notes.javaee.servlet.cookie; // 导入必需的 java 库 import java.io.*; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; // 扩展 HttpServlet 类 @WebServlet("/servlet/cookie/readCookies") public class ReadCookies extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, Cookie cookie = null; Cookie[] cookies = null; // 获取与该域相关的 Cookies 的数组 cookies = request.getCookies(); // 设置响应内容类型 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String title = "Reading Cookies Example"; String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n"; out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n"); if (cookies != null) { out.println("<h2>查找 Cookies 名称和值</h2>"); for (int i = 0; i < cookies.length; i++) { cookie = cookies[i]; out.print("名称:" + cookie.getName() + ","); out.print("值:" + cookie.getValue() + " <br/>"); } } else { out.println("<h2>未找到 Cookies</h2>"); } out.println("</body>"); out.println("</html>"); } } |
删除Cookie
Java中并没有提供直接删除Cookie的方法,如果想要删除一个Cookie,直接将这个Cookie的有效期设为0就可以了。步骤如下:
(1)读取一个现有的 cookie,并把它存储在 Cookie 对象中。
(2)使用
setMaxAge() 方法设置
cookie 的年龄为零,来删除现有的 cookie。
(3)把这个
cookie 添加到响应头。
DeleteCookieDemo.java
package notes.javaee.servlet.cookie; // 导入必需的 java 库 import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; // 扩展 HttpServlet 类 @WebServlet("/servlet/cookie/deleteCookieDemo") public class DeleteCookieDemoextends HttpServlet { private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, Cookie cookie = null; Cookie[] cookies = null; // 获取与该域相关的 Cookies 的数组 cookies = request.getCookies(); // 设置响应内容类型 response.setContentType("text/html"); response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); String title = "Delete Cookies Example"; String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n"; out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n"); if (cookies != null) { out.println("<h2>Cookies 名称和值</h2>"); for (int i = 0; i < cookies.length; i++) { cookie = cookies[i]; if ((cookie.getName()).compareTo("name") == 0) { cookie.setMaxAge(0); response.addCookie(cookie); out.print("已删除的 cookie:" + cookie.getName() + "<br/>"); } out.print("名称:" + cookie.getName() + ","); out.print("值:" + cookie.getValue() + " <br/>"); } } else { out.println( "<h2 class=\"tutheader\">No cookies } out.println("</body>"); out.println("</html>"); } } |