好久没写博客了,一直没什么好写的,最近碰到JSESSIONID这个问题,网上的说法有点模糊,特别是什么时候会出现URL重写这个问题,有些说客户端禁用Cookie,有些说第一次访问,这里总结一下
JSESSIONID是什么
老实说一开始看到这个有点懵,写Java这么久没看过这东西。
首先,JSESSIONID是一个Cookie,Servlet容器(tomcat,jetty)用来记录用户session。
什么时候种下JSESSIONID
创建会话时,即调用request.getSession()的时候,关于getSession就不说了。补充几点是,访问html是不会创建session的,JSP页面默认是会创建session的,可以在JSP页面里面关掉自动创建session
URL重写
服务端在内存里创建session,需要种Cookie,除了在request header里面设置Set-Cookie以外,tomcat等容器有一个URL重写机制。这个机制是客户端Cookie不可用时的一个兜底策略,通过在URL后面加上;jsessionid=xxx来传递session id,这样即使Cookie不可用时,也可以保证session的可用性,但是session暴露在URL里,本身是不安全的,到这里基本网上说法都是一致的
但是最关键的问题,tomcat怎么知道客户端Cookie不可用。我在idea导入tomcat的源码调试跟踪,不同版本有些出入,大致应该还是一样的
tomcat有一个org.apache.catalina.connector.Response是Response的落地类,有两个方法会进行URL重写,分别是encodeRedirectURL
和encodeURL
,encodeRedirectURL
是重定向时会被调用,encodeURL
貌似是手动调用,所以默认情况,重定向时才会出现URL重写。两个方法代码类似,下面只关注encodeRedirectURL
/**
* Encode the session identifier associated with this response
* into the specified redirect URL, if necessary.
*
* @param url URL to be encoded
* @return <code>true</code> if the URL was encoded
*/
@Override
public String encodeRedirectURL(String url) {
if (isEncodeable(toAbsolute(url))) {
return (toEncoded(url, request.getSessionInternal().getIdInternal()));
} else {
return (url);
}
}
方法注释写得很清楚了,如果有必要的话,把session id塞到重定向的URL里面。再看一下isEncodeable
方法,关键地方我加了中文注释
/**
* Return <code>true</code> if the specified URL should be encoded with
* a session identifier. This will be true if all of the following
* conditions are met:
* <ul>
* <li>The request we are responding to asked for a valid session
* <li>The requested session ID was not received via a cookie
* <li>The specified URL points back to somewhere within the web
* application that is responding to this request
* </ul>
*
* @param location Absolute URL to be validated
* @return <code>true</code> if the URL should be encoded
*/
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;
final Session session = hreq.getSessionInternal(false);
if (session == null) {
return false;
}
//这里其实就是网上说的客户端禁用Cookie
if (hreq.isRequestedSessionIdFromCookie()) {
return false;
}
// Is URL encoding permitted
// servlet3.0后可以在项目web.xml里关掉URL重写,对应tomat7之后
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 {
//这个方法会重写URL
return doIsEncodeable(hreq, session, location);
}
}
其中调用Request
对象的isRequestedSessionIdFromCookie
判断客户端Cookie是否可用,里面逻辑也很简单,就是读取request里面有没有传JSESSIONID这个Cookie。所以网上有些人说第一次访问,其实只要客户端没有传JSESSIONID,tomcat都假定Cookie不可用
网友评论