一. 需求.
我們公司要對自己的各個網站進行數據採集,想了解一個用戶在我們網站的整個瀏覽軌跡,但是我們每個二級域名都對應自己的項目,也就是說對應自己的jsessionid,我們無法把這些數據關聯起來,所以想到讓所有的二級域名都公用一個jsessionid,這樣用戶的整個瀏覽數據我們就都能得到了。
二. 開發。
需要對tomcat(jboss-web)的源碼進行修改,修改的地方有兩處。
1.org.apache.catalina.connector.Request的configureSessionCookie方法
/** * Configures the given JSESSIONID cookie. * * @param cookie The JSESSIONID cookie to be configured */ protected void configureSessionCookie(TomcatCookie cookie) { cookie.setMaxAge(-1); if (context.getSessionCookie().getPath() != null) { cookie.setPath(context.getSessionCookie().getPath()); } else { String contextPath = context.getEncodedPath(); if ("".equals(contextPath)) { contextPath = "/"; } cookie.setPath(contextPath); } if (context.getSessionCookie().getComment() != null) { cookie.setComment(context.getSessionCookie().getComment()); } if (context.getSessionCookie().getDomain() != null) { cookie.setDomain(context.getSessionCookie().getDomain()); } if (context.getSessionCookie().isHttpOnly()) { cookie.setHttpOnly(true); } cookie.setPath("/"); cookie.setDomain(System.getProperty("cookieDomain")); if (context.getSessionCookie().isSecure()) { cookie.setSecure(true); } else if (isSecure()) { cookie.setSecure(true); } }
添加的代碼是
cookie.setPath("/"); cookie.setDomain(System.getProperty("cookieDomain"));
2.在編譯好的tomcat中修改conf下的catalina.properties
添加cookieDomain變量 cookieDomain=.cdeledu.com
三.原理
tomcat如何讀取客戶端的jsessionid
向tomcat請求過程中,需要訪問org.apache.catalina.connector.CoyoteAdapter的sevice方法,裏面調用了postParseRequest方法,這個方法就是主要解析客戶端的jsessionid,其中parseSessionId主要是分析url裏的jessionID,parseSessionCookiesId這個是分析cookie中的jsessionid
代碼如下:
從url獲得jsesionid
/** * Parse session id in URL. */ protected void parseSessionId(org.apache.coyote.Request req, Request request) { ByteChunk uriBC = req.requestURI().getByteChunk(); //math的值爲:";jsessionid=" ,判斷url中是否有這個字符串 int semicolon = uriBC.indexOf(match, 0, match.length(), 0); //如果有解析,並賦值給request(org.apache.catalina.connector.Request) if (semicolon > 0) { // Parse session ID, and extract it from the decoded request URI int start = uriBC.getStart(); int end = uriBC.getEnd(); int sessionIdStart = semicolon + match.length(); int semicolon2 = uriBC.indexOf(';', sessionIdStart); if (semicolon2 >= 0) { request.setRequestedSessionId (new String(uriBC.getBuffer(), start + sessionIdStart, semicolon2 - sessionIdStart)); // Extract session ID from request URI byte[] buf = uriBC.getBuffer(); for (int i = 0; i < end - start - semicolon2; i++) { buf[start + semicolon + i] = buf[start + i + semicolon2]; } uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon); } else { request.setRequestedSessionId (new String(uriBC.getBuffer(), start + sessionIdStart, (end - start) - sessionIdStart)); uriBC.setEnd(start + semicolon); } request.setRequestedSessionURL(true); } else { request.setRequestedSessionId(null); request.setRequestedSessionURL(false); } }
從cookie中獲取
/** * Parse session id in URL. */ protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { // Parse session id from cookies 獲取request中的cookie Cookies serverCookies = req.getCookies(); int count = serverCookies.getCookieCount(); if (count <= 0) return; for (int i = 0; i < count; i++) { ServerCookie scookie = serverCookies.getCookie(i); //判斷cookie中有name爲jsessionid的, //有就賦值給request(org.apache.catalina.connector.Request) if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) { // Override anything requested in the URL if (!request.isRequestedSessionIdFromCookie()) { // Accept only the first session id cookie convertMB(scookie.getValue()); request.setRequestedSessionId (scookie.getValue().toString()); request.setRequestedSessionCookie(true); request.setRequestedSessionURL(false); if (log.isDebugEnabled()) log.debug(" Requested cookie session id is " + request.getRequestedSessionId()); } else { if (!request.isRequestedSessionIdValid()) { // Replace the session id until one is valid convertMB(scookie.getValue()); request.setRequestedSessionId (scookie.getValue().toString()); } } } } }
由於咱們寫到的是主域下,所以在tomcat中能獲得這個cookie(tomcat中能獲得的cookie的範圍爲自己域名下和主域下的)。