1.2.6 Session 对浏览器的要求
虽然 Session 保存在服务器, 对客户端是透明的, 它的正常运行仍然需要客户端浏览器的支持. 这是因为 Session 需要使用 Cookie 作为识别标志. HTTP 协议是无状态的, Session 不能依据 HTTP 连接来判断是否为同一客户, 因此服务器向客户端浏览器发送一个名为 JSESSIONID 的 Cookie, 它的值为该 Session 的 id(也就是 HttpSession.getId()的返回值).Session 依据该 Cookie 来识别是否为同一用户.
该 Cookie 为服务器自动生成的, 它的 maxAge 属性一般为 - 1, 表示仅当前浏览器内有效, 并且各浏览器窗口间不共享, 关闭浏览器就会失效.
因此同一机器的两个浏览器窗口访问服务器时, 会生成两个不同的 Session. 但是由浏览器窗口内的链接, 脚本等打开的新窗口 (也就是说不是双击桌面浏览器图标等打开的窗口) 除外. 这类子窗口会共享父窗口的 Cookie, 因此会共享一个 Session.
注意: 新开的浏览器窗口会生成新的 Session, 但子窗口除外. 子窗口会共用父窗口的 Session. 例如, 在链接上右击, 在弹出的快捷菜单中选择 "在新窗口中打开" 时, 子窗口便可以访问父窗口的 Session.
如果客户端浏览器将 Cookie 功能禁用, 或者不支持 Cookie 怎么办? 例如, 绝大多数的手机浏览器都不支持 Cookie.Java web 提供了另一种解决方案: URL 地址重写.
1.2.7 URL 地址重写
URL 地址重写是对客户端不支持 Cookie 的解决方案. URL 地址重写的原理是将该用户 Session 的 id 信息重写到 URL 地址中. 服务器能够解析重写后的 URL 获取 Session 的 id. 这样即使客户端不支持 Cookie, 也可以使用 Session 来记录用户状态. HttpServletResponse 类提供了 encodeURL(Stringurl)实现 URL 地址重写, 例如:
- <td>
- <a href="<%=response.encodeURL(" index.jsp?c=1&wd=Java ") %>">
- Homepage
- </a>
- </td>
该方法会自动判断客户端是否支持 Cookie. 如果客户端支持 Cookie, 会将 URL 原封不动地输出来. 如果客户端不支持 Cookie, 则会将用户 Session 的 id 重写到 URL 中. 重写后的输出可能是这样的:
- <td>
- <ahref="index.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E?c=
- 1&wd=Java">
- Homepage
- </a>
- </td>
即在文件名的后面, 在 URL 参数的前面添加了字符串 ";jsessionid=XXX". 其中 XXX 为 Session 的 id. 分析一下可以知道, 增添的 jsessionid 字符串既不会影响请求的文件名, 也不会影响提交的地址栏参数. 用户单击这个链接的时候会把 Session 的 id 通过 URL 提交到服务器上, 服务器通过解析 URL 地址获得 Session 的 id.
如果是页面重定向(Redirection),URL 地址重写可以这样写:
- <%
- if("administrator".equals(userName))
- {
- response.sendRedirect(response.encodeRedirectURL("administrator.jsp"));
- return;
- }
- %>
效果跟 response.encodeURL(String url)是一样的: 如果客户端支持 Cookie, 生成原 URL 地址, 如果不支持 Cookie, 传回重写后的带有 jsessionid 字符串的地址.
对于 WAP 程序, 由于大部分的手机浏览器都不支持 Cookie,WAP 程序都会采用 URL 地址重写来跟踪用户会话. 比如用友集团的移动商街等.
注意: TOMCAT 判断客户端浏览器是否支持 Cookie 的依据是请求中是否含有 Cookie. 尽管客户端可能会支持 Cookie, 但是由于第一次请求时不会携带任何 Cookie(因为并无任何 Cookie 可以携带),URL 地址重写后的地址中仍然会带有 jsessionid. 当第二次访问时服务器已经在浏览器中写入 Cookie 了, 因此 URL 地址重写后的地址中就不会带有 jsessionid 了.
1.2.8 Session 中禁止使用 Cookie
既然 WAP 上大部分的客户浏览器都不支持 Cookie, 索性禁止 Session 使用 Cookie, 统一使用 URL 地址重写会更好一些. Java Web 规范支持通过配置的方式禁用 Cookie. 下面举例说一下怎样通过配置禁止使用 Cookie.
打开项目 sessionWeb 的 WebRoot 目录下的 META-INF 文件夹(跟 Web-INF 文件夹同级, 如果没有则创建), 打开 context.xml(如果没有则创建), 编辑内容如下:
代码 1.11 /META-INF/context.xml
- <?xml version='1.0' encoding='UTF-8'?>
- <Context path="/sessionWeb"cookies="false">
- </Context>
或者修改 Tomcat 全局的 conf/context.xml, 修改内容如下:
代码 1.12 context.xml
- <!-- The contents of this file will be loaded for eachweb application -->
- <Context cookies="false">
- <!-- ... 中间代码略 -->
- </Context>
部署后 TOMCAT 便不会自动生成名 JSESSIONID 的 Cookie,Session 也不会以 Cookie 为识别标志, 而仅仅以重写后的 URL 地址为识别标志了.
注意: 该配置只是禁止 Session 使用 Cookie 作为识别标志, 并不能阻止其他的 Cookie 读写. 也就是说服务器不会自动维护名为 JSESSIONID 的 Cookie 了, 但是程序中仍然可以读写其他的 Cookie.
深入理解 HTTP Session
session 在 Web 开发中是一个非常重要的概念, 这个概念很抽象, 很难定义, 也是最让人迷惑的一个名词, 也是最多被滥用的名字之一, 在不同的场合, session 一次的含义也很不相同. 这里只探讨 HTTP Session.
为了说明问题, 这里基于 Java Servlet 理解 Session 的概念与原理, 这里所说 Servlet 已经涵盖了 JSP 技术, 因为 JSP 最终也会被编译为 Servlet, 两者有着相同的本质.
在 Java 中, HTTP 的 Session 对象用 javax.servlet.http.HttpSession 来表示.
1, 概念: Session 代表服务器与浏览器的一次会话过程, 这个过程是连续的, 也可以时断时续的. 在 Servlet 中, session 指的是 HttpSession 类的对象, 这个概念到此结束了, 也许会很模糊, 但只有看完本文, 才能真正有个深刻理解.
2,Session 创建的时间是:
一个常见的误解是以为 session 在有客户端访问时就被创建, 然而事实是直到某 server 端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建, 注意如果 JSP 没有显示的使用 <% @page session="false"%> 关闭 session, 则 JSP 文件在编译成 Servlet 时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true); 这也是 JSP 中隐含的 session 对象的来历.
由于 session 会消耗内存资源, 因此, 如果不打算使用 session, 应该在所有的 JSP 中关闭它.
引申:
1), 访问 *.html 的静态资源因为不会被编译为 Servlet, 也就不涉及 session 的问题.
2), 当 JSP 页面没有显式禁止 session 的时候, 在打开浏览器第一次请求该 jsp 的时候, 服务器会自动为其创建一个 session, 并赋予其一个 sessionID, 发送给客户端的浏览器. 以后客户端接着请求本应用中其他资源的时候, 会自动在请求头上添加:
Cookie:JSESSIONID = 客户端第一次拿到的 session ID
这样, 服务器端在接到请求时候, 就会收到 session ID, 并根据 ID 在内存中找到之前创建的 session 对象, 提供给请求使用. 这也是 session 使用的基本原理 ---- 搞不懂这个, 就永远不明白 session 的原理.
3,Session 删除的时间是:
1)Session 超时: 超时指的是连续一定时间服务器没有收到该 Session 所对应客户端的请求, 并且这个时间超过了服务器设置的 Session 超时的最大时间.
2)程序调用 HttpSession.invalidate()
3)服务器关闭或服务停止
4,session 存放在哪里: 服务器端的内存中. 不过 session 可以通过特殊的方式做持久化管理.
5,session 的 id 是从哪里来的, sessionID 是如何使用的: 当客户端第一次请求 session 对象时候, 服务器会为客户端创建一个 session, 并将通过特殊算法算出一个 session 的 ID, 用来标识该 session 对象, 当浏览器下次 (session 继续有效时) 请求别的资源的时候, 浏览器会偷偷地将 sessionID 放置到请求头中, 服务器接收到请求后就得到该请求的 sessionID, 服务器找到该 id 的 session 返还给请求者 (Servlet) 使用. 一个会话只能有一个 session 对象, 对 session 来说是只认 id 不认人.
6,session 会因为浏览器的关闭而删除吗?
不会, session 只会通过上面提到的方式去关闭.
7, 同一客户端机器多次请求同一个资源, session 一样吗?
一般来说, 每次请求都会新创建一个 session.
其实, 这个也不一定的, 总结下: 对于多标签的浏览器 (比如 360 浏览器) 来说, 在一个浏览器窗口中, 多个标签同时访问一个页面, session 是一个. 对于多个浏览器窗口之间, 同时或者相隔很短时间访问一个页面, session 是多个的, 和浏览器的进程有关. 对于一个同一个浏览器窗口, 直接录入 url 访问同一应用的不同资源, session 是一样的.
8,session 是一个容器, 可以存放会话过程中的任何对象.
9,session 因为请求 (request 对象) 而产生, 同一个会话中多个 request 共享了一 session 对象, 可以直接从请求中获取到 session 对象.
10, 其实, session 的创建和使用总在服务端, 而浏览器从来都没得到过 session 对象. 但浏览器可以请求 Servlet(jsp 也是 Servlet)来获取 session 的信息. 客户端浏览器真正紧紧拿到的是 session ID, 而这个对于浏览器操作的人来说, 是不可见的, 并且用户也无需关心自己处于哪个会话过程中.
来源: http://www.bubuko.com/infodetail-2962180.html