在Cookie被禁用的情况下使用url rewrite机制保持Session

来源:互联网 发布:淘宝店铺全屏代码设置 编辑:程序博客网 时间:2024/05/01 19:13
最近在做QQ空间上的应用时,遇到session丢失的问题,明明把登录用户的信息存在session里了,但是再访问时,就找不到了,session是一个新的session,也就是说,每次访问都被认为是一个新的session。


寻找原因:由于我们的程序是跑在QQ空间里,是QQ空间的应用页面提供一个iframe给我们展示我们的程序页面,iframe里和iframe外分别是不同的域名,问题出在这里,跨域情况下的cookie被称作“第三方cookies”,第三方cookies是不被支持的,所以,cookie不能被顺利地带到server端,因此,靠cookie来维持的session自然就丢失了。到目前为止,我实际测试:chrome和firefox没有做限制,IE 11下,将第三方域名添加到“受信任的站点”后可以带Cookie,Safari浏览器下禁用Cookie。


但是不能要求用户去添加“受信任的站点”啊,如果仅仅针对IE浏览器,可以用P3P解决方案:
详见http://blog.csdn.net/wauit/article/details/9875157


但是P3P对Safari浏览器不起作用。


于是,我们不得不自己找解决方案了。
JAVA EE的规范说:当cookie不能用时,使用url rewrite机制来保持session。这个大家都知道,只是长时间以来,我们习惯于在cookie环境下开发,不去理会这个特性了。那么url rewrite是怎么工作的呢?


在tomcat下,默认的设置就是:优先使用cookie,如果cookie被禁用,使用url rewrite,所以,不用修改任何配置。但是我们的代码要写东西:


先说一个不太好的解决方案:response.encodeURL(String);看一下这个方法,注意,还有另外一个方法叫response.encodeUrl(String),是被弃用的API。
这个方法的功能是:把
http://xxx.com/abc?a=b
这样的url变成:
http://xxx.com/abc;jsessionid=D97956894C4330053A84DBE6FA7E8AC2?a=b
这样的url。


按理说我们应该把应用中每个链接上都套上这个方法,但是,一来太麻烦了,二来,没有判断cookie是否可用,如果cookie可用,cookie还是更好的方案,因为不必在url上带上session信息,以免拷贝分享一个URL时带上不必要的session信息。


其实,JSTL早就有解决方案,现在的JSTL也更方便使用了,我下载最新的1.2.1版本,比原来的1.1更加方便,直接加入jar包,在jsp头上引用<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>就可以使用core标签了。


<a href='<c:url value="/abc?a=b"/>'>链接</a>
生成的html:
<a href='/app/abc?abc;jsessionid=D97956894C4330053A84DBE6FA7E8AC2?a=b'>链接</a>


所以,以后不要再写href="/app/abc?a=b"这样的代码了,都用<c:url/>来代替吧,好处有:
1. 自动判断cookie是否可用,如果可用,返回原值,如果不可用,返回带jsessionid的URL
2. 自动补充ContextPath,例如我们正常应该写href="<%=request.getContextPath()%>/abc?a=b",用c:url就不用写这个context path了,直接<c:url value="/abc?a=b"/>
3. 自动对URL进行base64编码,例如
<c:url value="/abc">
<c:param name="a" value="中文"/>
</c:url>
生成的url是:/app/abc?a=%e4%b8%ad%e6%96%87'>链接</a>
在实际使用中可以先定义好,再引用,也可以直接inline在href中:
<c:url value="/abc" var="avarname">
<c:param name="a" value="中文"/>
</c:url>
<a href="${avarname}">链接</a>
或者inline:
<a href='<c:url value="/abc" var="avarname"><c:param name="a" value="中文"/></c:url>'>链接</a>
4. 可以在后面再拼想要的参数:例如:
<a href='<c:url value="/abc?a=b"/>&v=<%=new java.util.Date().getTime()%>'>链接</a>


小提示:
1. 我通常在inline使用<c:url/>时,href的值用单引号,这是为了区别里面value=""的双引号,实际上,两部分都使用双引号也是支持的。
2. 图片、css、javascript等不需要保持session的url就不要加了,一个是加大了不必要的运算量,另外,有些浏览器是异步加载的,可能你的登录存session的动作还没做完呢,图片的请求就到了,所以对这种请求做session没有意义。
3. 第三方cookies已被认识到是不安全的,虽然现在有些浏览器还没有做限制,但从趁势上看是会越来越限制的,而随着开放平台的成熟,我们的程序非常有可能有一天被放到开发平台上去运行,所以,还是要多考虑cookie禁用的情况。而且,随着集群的普遍应用,session也越来越不存在于单机了,这个是另外一个话题,session的用法将会有很大的变化。
0 0