Cookie,Session
本文主要介绍Servlet对Cookies与Session的处理。因此在此之前,我们先了解什么是Cookie和Session。
无状态HTTP
HTTP 的无状态是指 HTTP
协议对事务处理是没有记忆能力的,也就是说服务器不知道客户端是什么状态。当我们向服务器发送请求后,服务器解析此请求,然后返回对应的响应,服务器负责完成这个过程,而且这个过程是完全独立的,服务器不会记录前后状态的变化,也就是缺少状态记录。这意味着如果后续需要处理前面的信息,则必须重传,这导致需要额外传递一些前面的重复请求,才能获取后续响应,然而这种效果显然不是我们想要的。为了保持前后状态,我们肯定不能将前面的请求全部重传一次,这太浪费资源了,对于这种需要用户登录的页面来说,更是棘手。
而Cookies与Session就是用于保持HTTP连接状态的技术。Session在服务端,也就是网站的服务器,用来保存用户的会话信息;Cookies 在客户端,也可以理解为浏览器端,有了
Cookies,浏览器在下次访问网页时会自动附带上它发送给服务器,服务器通过识别 Cookies 并鉴定出是哪个用户,然后再判断用户是否是登录状态,然后返回对应的响应。
我们可以理解为 Cookies 里面保存了登录的凭证,有了它,只需要在下次请求携带 Cookies 发送请求而不必重新输入用户名、密码等信息重新登录了。
Session
在 Web 中,会话对象用来存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在会话对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web
页时,如果该用户还没有会话,则 Web 服务器将自动创建一个会话对象。当会话过期或被放弃后,服务器将终止该会话。
Cookies
Cookies 指某些网站为了辨别用户身份、进行会话跟踪而存储在用户本地终端上的数据。
Cookies属性结构
- Name,即该 Cookie 的名称。Cookie 一旦创建,名称便不可更改
- Value,即该 Cookie 的值。如果值为 Unicode 字符,需要为字符编码。如果值为二进制数据,则需要使用 BASE64 编码。
- Max Age,即该 Cookie 失效的时间,单位秒,也常和 Expires 一起使用,通过它可以计算出其有效时间。Max Age 如果为正数,则该 Cookie 在 Max Age 秒之后失效。如果为负数,则关闭浏览器时
Cookie 即失效,浏览器也不会以任何形式保存该 Cookie。 - Path,即该 Cookie 的使用路径。如果设置为 /path/,则只有路径为 /path/ 的页面可以访问该 Cookie。如果设置为 /,则本域名下的所有页面都可以访问该 Cookie。
- Domain,即可以访问该 Cookie 的域名。例如如果设置为 .zhihu.com,则所有以 zhihu.com,结尾的域名都可以访问该 Cookie。
- Size 字段,即此 Cookie 的大小。
- Http 字段,即 Cookie 的 httponly 属性。若此属性为 true,则只有在 HTTP Headers 中会带有此 Cookie 的信息,而不能通过 document.cookie 来访问此 Cookie。
- Secure,即该 Cookie 是否仅被使用安全协议传输。安全协议。安全协议有 HTTPS,SSL 等,在网络上传输数据之前先将数据加密。默认为 false。
会话维持
当客户端第一次请求服务器时,服务器会返回一个响应头中带有 Set-Cookie 字段的响应给客户端,用来标记是哪一个用户,客户端浏览器会把 Cookies 保存起来。当浏览器下一次再请求该网站时,浏览器会把此 Cookies
放到请求头一起提交给服务器,Cookies 携带了会话 ID 信息,服务器检查该 Cookies 即可找到对应的会话是什么,然后再判断会话来以此来辨认用户状态。
在成功登录某个网站时,服务器会告诉客户端设置哪些 Cookies 信息,在后续访问页面时客户端会把 Cookies
发送给服务器,服务器再找到对应的会话加以判断。如果会话中的某些设置登录状态的变量是有效的,那就证明用户处于登录状态,此时返回登录之后才可以查看的网页内容,浏览器再进行解析便可以看到了。
反之,如果传给服务器的 Cookies 是无效的,或者会话已经过期了,我们将不能继续访问页面,此时可能会收到错误的响应或者跳转到登录页面重新登录。
所以,Cookies 和会话需要配合,一个处于客户端,一个处于服务端,二者共同协作,就实现了登录会话控制。
会话 Cookie 和持久 Cookie
从表面意思来说,会话 Cookie 就是把 Cookie 放在浏览器内存里,浏览器在关闭之后该 Cookie 即失效;持久 Cookie 则会保存到客户端的硬盘中,下次还可以继续使用,用于长久保持用户登录状态。
其实严格来说,没有会话 Cookie 和持久 Cookie 之分,只是由 Cookie 的 Max Age 或 Expires 字段决定了过期的时间。
因此,一些持久化登录的网站其实就是把 Cookie 的有效时间和会话有效期设置得比较长,下次我们再访问页面时仍然携带之前的 Cookie,就可以直接保持登录状态。
Servlet Cookie 处理
通过 Servlet 设置 Cookie
- 创建一个 Cookie 对象:您可以调用带有 cookie 名称和 cookie 值的 Cookie 构造函数,cookie 名称和 cookie 值都是字符串。
1 | Cookie cookie = new Cookie("key","value"); |
注意:’key’, ‘value’中不应该出现空格和[ ] ( ) = , “ / ? @ : ; 等字符。
- 设置最大生存周期:您可以使用 setMaxAge 方法来指定 cookie 能够保持有效的时间(以秒为单位)。
1 | cookie.setMaxAge(60*60*24); //最长有效期24小时 |
- 发送 Cookie 到 HTTP 响应头:您可以使用 response.addCookie 来添加 HTTP 响应头中的 Cookie。
1 | response.addCookie(cookie); |
通过 Servlet 读取 Cookie
要读取 Cookie,您需要通过调用 HttpServletRequest 的 getCookies( ) 方法创建一个 javax.servlet.http. Cookie 对象的数组。然后循环遍历数组,并使用 getName() 和
getValue() 方法来访问每个 cookie 和关联的值。
1 | Cookie cookie = null; |
通过 Servlet 删除 Cookie
- 读取一个现有的 cookie,并把它存储在 Cookie 对象中。
- 使用 setMaxAge() 方法设置 cookie 的年龄为零,来删除现有的 cookie。
- 把这个 cookie 添加到响应头。
1 | Cookie cookie = null; |
Cookie API
column0 | column1 |
---|---|
序号 | 方法 & 描述 |
1 | public void setDomain(String pattern)。该方法设置 cookie 适用的域,例如 nanaiii.com。 |
2 | public String getDomain()。该方法获取 cookie 适用的域,例如 nanaiii.com。 |
3 | public void setMaxAge(int expiry)。该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。 |
4 | public int getMaxAge()。该方法返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示 cookie 将持续下去,直到浏览器关闭。 |
5 | public String getName()。该方法返回 cookie 的名称。名称在创建后不能改变。 |
6 | public void setValue(String newValue)。该方法设置与 cookie 关联的值。 |
7 | public String getValue()。该方法获取与 cookie 关联的值。 |
8 | public void setPath(String uri)。该方法设置 cookie 适用的路径。如果您不指定路径,与当前页面相同目录下的(包括子目录下的)所有 URL 都会返回 cookie。 |
9 | public String getPath()。该方法获取 cookie 适用的路径。 |
10 | public void setSecure(boolean flag)。该方法设置布尔值,表示 cookie 是否应该只在加密的(即 SSL)连接上发送。 |
11 | public void setComment(String purpose)。设置cookie的注释。该注释在浏览器向用户呈现 cookie 时非常有用。 |
12 | public String getComment()。获取 cookie 的注释,如果 cookie 没有注释则返回 null。 |
Servlet Session 跟踪
Servlet 提供了 HttpSession 接口,该接口提供了一种跨多个页面请求或访问网站时识别用户以及存储有关用户信息的方式。
Servlet 容器使用这个接口来创建一个 HTTP 客户端和 HTTP 服务器之间的 session 会话。会话持续一个指定的时间段,跨多个连接或页面请求。
你需要在向客户端发送任何文档内容之前调用 request.getSession()来获取 HttpSession 对象。如下所示: HttpSession session = request.getSession();
下面展示如何使用 HttpSession 对象获取 session 会话创建时间和最后访问时间。
1 | // 如果不存在 session 会话,则创建一个 session 对象 |
删除 Session 会话数据
当您完成了一个用户的 session 会话数据,您有以下几种选择:
移除一个特定的属性:您可以调用 public void removeAttribute(String name) 方法来删除与特定的键相关联的值。
删除整个 session 会话:您可以调用 public void invalidate() 方法来丢弃整个 session 会话。
设置 session 会话过期时间:您可以调用 public void setMaxInactiveInterval(int interval) 方法来单独设置 session 会话超时。
注销用户:如果使用的是支持 servlet 2.4 的服务器,您可以调用 logout 来注销 Web 服务器的客户端,并把属于所有用户的所有 session 会话设置为无效。
web.xml 配置:如果您使用的是 Tomcat,除了上述方法,您还可以在 web.xml 文件中配置 session 会话超时,如下所示:
1 | <session-config> |
HttpSession API
column0 | column1 |
---|---|
序号 | 方法 & 描述 |
1 | public Object getAttribute(String name)。该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null。 |
2 | public Enumeration getAttributeNames()。该方法返回 String 对象的枚举,String 对象包含所有绑定到该 session 会话的对象的名称。 |
3 | public long getCreationTime()。该方法返回该 session 会话被创建的时间,自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。 |
4 | public String getId()。该方法返回一个包含分配给该 session 会话的唯一标识符的字符串。 |
5 | public long getLastAccessedTime()。该方法返回客户端最后一次发送与该 session 会话相关的请求的时间自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。 |
6 | public int getMaxInactiveInterval()。该方法返回 Servlet 容器在客户端访问时保持 session 会话打开的最大时间间隔,以秒为单位。 |
7 | public void invalidate()。该方法指示该 session 会话无效,并解除绑定到它上面的任何对象。 |
8 | public boolean isNew()。如果客户端还不知道该 session 会话,或者如果客户选择不参入该 session 会话,则该方法返回 true。 |
9 | public void removeAttribute(String name)。该方法将从该 session 会话移除指定名称的对象。 |
10 | public void setAttribute(String name, Object value)。该方法使用指定的名称绑定一个对象到该 session 会话。 |
11 | public void setMaxInactiveInterval(int interval)。该方法在 Servlet 容器指示该 session 会话无效之前,指定客户端请求之间的时间,以秒为单位。 |