java web中, 用session来表示用户浏览器(客户端)与服务器建立的一次会话。
通常用sessionId来标记一个session,在Java中,有很简单的方式直接获取sessionId;
HttpSession session = request.getSession(); String sessionId = session.getId();
但是sessionId并不是session的特性,实际上,sessionId是在客户端首次创建会话时将生成的sessionId存入cookie中,在之后的访问中直接读取这个id值。
当客户端禁止了cookie行为后,SessionId在每次刷新页面时都会更新,利用id来表示会话也成为了妄想,此篇文章意在说明,如何操作能使SessionId能够独立于cookie使用。
这种操作其实在shiro中已经被应用了,当我们进入登录页面中,url后会出现";jssionid=xxxxxx",将sessionid显示的标注在url中,可以使用:
response.encodeURL(url);
当cookie被禁用时,该方法会在url后面添加字符,返回一个带有sessionid的url字符串,Java中会自动从中获取sessionId,可以直接使用如下方法处理我们要做转发的请求url:
response.encodeRedirectURL(request.getRequestURI());
注意,encodeURL底层中核心逻辑代码是这样的:
@Override public String encodeURL(String url) { //绝对url String absolute; try { absolute = toAbsolute(url); } catch (IllegalArgumentException iae) { // Relative URL return url; } if (isEncodeable(absolute)) { // W3c spec clearly said if (url.equalsIgnoreCase("")) { url = absolute; } else if (url.equals(absolute) && !hasPath(url)) { url += '/'; } return (toEncoded(url, request.getSessionInternal().getIdInternal())); } else { return (url); } } protected boolean isEncodeable(final String location) { if (location == null) { return false; } // Is this an intra-document reference? if (location.startsWith("#")) { return false; } // Are we in a valid session that is not using cookies? final Request hreq = request; //这里的false指若session为空,不自动生成session final Session session = hreq.getSessionInternal(false); //这里session if (session == null) { return false; } //判断如果session来自cookie,则不作url处理 if (hreq.isRequestedSessionIdFromCookie()) { return false; } // Is URL encoding permitted if (!hreq.getServletContext().getEffectiveSessionTrackingModes(). contains(SessionTrackingMode.URL)) { return false; } if (SecurityUtil.isPackageProtectionEnabled()) { return ( AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run(){ return Boolean.valueOf(doIsEncodeable(hreq, session, location)); } })).booleanValue(); } else { return doIsEncodeable(hreq, session, location); } }
很多版本的包中,判断session是否为空时,并没有生成新的session,若是用户禁止cookie,程序中也不会生成session,最终还是不能正确的做请求跳转,所以在跳转前,先做request.getSession()处理。
获取url之后,我们要手动处理逻辑,可以使用拦截器进行统一内容处理,在拦截器中:
request.getSession(true); String url=response.encodeURL(request.getRequestURI()); //不作处理会死循环 if(!url.equals(request.getRequestURI())){ try { response.sendRedirect(url); } catch (IOException e) { //do something } }else{ }