tomcat 二級域名 相關(guān)
tomcat 二級域名 session共享 Tomcat 2010-08-02 19:16:09 閱讀19 評論0 字號:大中小 訂閱Tomcat 下,不同的二級域名之間或根域與子域之間,Ses
tomcat 二級域名 session共享 Tomcat 2010-08-02 19:16:09 閱讀19 評論0 字號:大中小 訂閱
Tomcat 下,不同的二級域名之間或根域與子域之間,Session 默認(rèn)是不共享的,因為Cookie 名稱為JSESSIONID 的Cookie 根域是默認(rèn)是沒設(shè)置 的,訪問不同的二級域名,其Cookie 就重新生成,而session 就是根據(jù)這個Cookie 來生成的,所以在不同的二級域名下生成的Session 也 不一樣。找到了其原因,就可根據(jù)這個原因?qū)omcat 在生成Session 時進(jìn)行相應(yīng)的修改(注:本文針對Tomcat 6.0.18) 。
修改tomcat 源代碼
包:catalina.jar
類:org.apache.catalina.connector.Request
protected void configureSessionCookie(Cookie cookie) {
cookie.setMaxAge(-1);
String contextPath = null;
if (!connector.getEmptySessionPath() && (getContext() != null)) {
contextPath = getContext().getEncodedPath();
}
if ((contextPath != null) && (contextPath.length() > 0)) { cookie.setPath(contextPath);
} else {
cookie.setPath("/");
}
String value = System.getProperty("webDomain");
if ((null !=value) && (value.length()>0) &&
(value.indexOf(".") != -1)) {
cookie.setDomain((value.startsWith("."))?value:"." value); }
if (isSecure()) {
cookie.setSecure(true);
}
}
重新編譯Tomcat :編譯tomcat
修改配置:tomcatconf?talina.properties,在最后添加一行
webDomain=***.com
,java 中的Cookie 和 Session
最近實現(xiàn)網(wǎng)頁訪問量及在線人數(shù)的統(tǒng)計,看到一篇好文章。轉(zhuǎn)之... 引用部分:
當(dāng)瀏覽器得到這個 sessionid會將它放在自己的進(jìn)程內(nèi)存里, 這里不同的瀏覽器會有所不同,IE 進(jìn)程間不能共享這個sessionid, 也就是新開一個IE 將不能共享 這個sessionid; 而Firefox 進(jìn)程間可以共享. 然后你繼續(xù)發(fā)請求給這個網(wǎng)站的時候, 瀏覽器就會把這個sessionid 放在請求頭里發(fā)送給該 服務(wù)器了, 這樣服務(wù)器得到sessionid 后再和自己內(nèi)存里存放的sessionid 對比鎖定客戶端, 從而區(qū)分不同客戶端, 完成會話.
可以看出如果用這種方式, 當(dāng)用戶在會話的過程中關(guān)閉瀏覽器結(jié)束進(jìn)程, 則這個sessionid 將消失, 如果用戶又打開瀏覽器想繼續(xù)這次會話的時候, 就會因 為發(fā)送的請求中沒有這個sessionid 而使服務(wù)器無法辨別該把那個session 信息給他, 注意(這個時候服務(wù)器端的sessionid 和 sessionid所指向的session 都還存在, 只是沒有正確的sessionid 和它匹配而占用服務(wù)器內(nèi)存, 只有session 過期或服務(wù)器重啟才 釋放內(nèi)存).
上面這種方式叫會話cookie , 把cookie 放在瀏覽器內(nèi)存里, 只能在這個瀏覽器的內(nèi)存范圍里完成會話, 是一種不長久的方式, 為了能長久會話, 就出現(xiàn)了持久化cookie , 把cookie 固化在用戶的計算機(jī)上, 現(xiàn)在的cookie 不單單能存放sessionid, 還能放用戶信息, 樣式表信息等.
如果用戶禁止了所有cookie 的使用, 那么會話cookie 和持久化cookie 都不能用了, 有個方案也可以解決問題, 就是URL 重寫, 這里要說下的就是URL 重寫只能實現(xiàn)會話cookie 的效果, 持久會話實現(xiàn)不了.
剛開始理解時,我也認(rèn)為會有持久和會話這兩種COOKIE 。我認(rèn)為,
會話COOKIE 就是用來存放SESSIONID 的,并且只存在于瀏覽器內(nèi)存,瀏覽器關(guān)閉后會話COOKIE 就被刪除;
持久COOKIE 就是用來存放其它信息,并且是在我們的本地硬盤里能看到的那種COOKIE 。
然后我寫了個SERVLET 試了一下。
Java 代碼
1. public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
2.
3. Cookie cookie = null;
4.
5. PrintWriter out = response.getWriter();
6. out.println("
");7.
,8. Cookie[] cookies = request.getCookies();
9.
10. // 如果沒有COOKIE ,新建一個COOKIE
11. if (cookies == null) {
12.
13. out.println("cookies is null."); 14.
15. cookie = new Cookie("new", "1");
16.
17. response.addCookie(cookie);
18.
19. } else {
20.
21. out.println("cookies is not null."); 22.
23. for (int i = 0; i < cookies.length; i ) { 24.
25. cookie = cookies[i];
26.
27. out.println("cookie" i " name: " cookie.getName() "");
28. }
29. }
30.
31. HttpSession session = request.getSession();
32.
33. if (session == null) {
34. out.println("session is null."); 35.
36. } else {
37. out.println("session is not null.");
38. out.println("session id: " session.getId() "");
39. }
40.
41. out.println("");
42.}
第一次訪問這個SERVLET ,頁面顯示
引用
,cookies is null.
session is not null.
session id: 0D0AABB6F911362FEE87BEEB2953C33F
第二次訪問,頁面顯示
引用
cookies is not null.
cookie0 name: new
cookie1 name: JSESSIONID
session is not null.
session id: 0D0AABB6F911362FEE87BEEB2953C33F
第二次訪問時從客戶端來了兩個COOKIE ,名為“new”的COOKIE 是我創(chuàng)建的,名為“JSESSIONID”的COOKIE 應(yīng)該是服務(wù)器TOMCAT 創(chuàng)建的,但這時,在本地硬盤里找不到這兩個COOKIE 的文件。
改一下SERVLET ,在創(chuàng)建名為“new”的COOKIE 時,加一句
Java 代碼
1. cookie.setMaxAge(1000);
然后本地硬盤里就有“new”這個COOKIE 了。
這下就有疑問了,在沒有設(shè)置COOKIE 存活期時,自己創(chuàng)建的SESSION 不會存到本地硬盤,會不會TOMCAT 創(chuàng)建的所謂的會話COOKIE 也是沒有設(shè)置存活期呢?
然后根據(jù)zddava 的博客(http://zddava.javaeye.com/blog/311053),找到了TOMCAT 里創(chuàng)建會話COOKIE 的代碼。
在
org.apache.catalina.connector.Request.java 里,
Java 代碼
1. protected void configureSessionCookie(Cookie cookie) {
2. cookie.setMaxAge(-1);
3. String contextPath = null;
4. if (!connector.getEmptySessionPath() && (getContext() != null)) {
5. contextPath = getContext().getEncodedPath();
6. }
7. if ((contextPath != null) && (contextPath.length() > 0)) {
8. cookie.setPath(contextPath);
,9. } else {
10. cookie.setPath("/");
11. }
12. if (isSecure()) {
13. cookie.setSecure(true);
14. }
15.}
cookie.setMaxAge(-1);使COOKIE 在瀏覽器被關(guān)閉時刪除。而且這里的cookie 和上面SERVLET 里的cookie 都是javax.servlet.http.Cookie 。
由 此得出結(jié)論,可能最開始是我理解錯了,COOKIE 并沒有會話COOKIE 和持久COOKIE 之分。我們本地創(chuàng)建的“持久COOKIE”和 WEB容器創(chuàng)建的“會話
COOKIE”都是一種COOKIE ,就是javax.servlet.http.Cookie 。只是WEB 容器把存活期設(shè)置成了 關(guān)閉瀏覽器時刪除而已(TOMCAT )。
首先談一下session 對象在web 開發(fā)中的創(chuàng)建以及sessionId 生成并返回客戶端的運(yùn)行機(jī)制。
session 對象當(dāng)客戶端首次訪問時,創(chuàng)建一個新的session 對象。并同時生成一個 sessionId,并在此次響應(yīng)中將sessionId 以響應(yīng)報文的方式返回客戶端瀏覽器內(nèi)存或以重寫url 方式送回客戶端,來保持整個會話,只要sever 端的這個session 對象沒有銷毀,以后再調(diào)用 request.getSession()時就直接根據(jù)客戶端的sessionId 來檢索server 端生成的session 對象并返回,不會再次去新 建,除非根據(jù)此sessionId 沒有檢索到session 對象。
下面是在IE 下測試,因為IE 6.0的一個BUG 就是IE 的隱私設(shè)置。即使是阻止所有cookie 時,也還是會以會話cookie 來保存sessionId 。所以下面都是以會話cookie 來討論的。
(1)在server 沒有關(guān)閉,并在session 對象銷毀時間內(nèi),當(dāng)客戶端再次來請求 server端的servlet 或jsp 時,將會將在第一次請求時生成的sessionId 并附帶在請求信息頭中并向server 端發(fā)送,server 端 收到sessionId 后根據(jù)此sessionId 會去搜索 (此過程是透明的)server 對應(yīng)的session 對象并直接返回這個session 對象,此時不會重新去建立一個新的session 對象。
(2)當(dāng)server 關(guān)閉(之前產(chǎn)生的session 對象也就消亡了) ,或session 對 象過了其銷毀時間后,瀏覽器窗口不關(guān),并在本瀏覽器窗口再次去請求sever 端的servlet 和jsp 時,此時同樣會將 sessionId(server關(guān)閉或session 銷毀時生成的 sessionId)發(fā)送到server 端,server 根據(jù)sessionId 去找其對應(yīng)的session 對象,但此時session 對象已經(jīng)不存在, 此時會重新生成一個新的session 對象,并生成新的sessionId 并同樣將這個新生成的sessionId 以響應(yīng)報文的形式送到瀏覽器內(nèi)存中。
,(3)當(dāng)server 沒有關(guān)閉,并session 對象在其銷毀時間內(nèi),當(dāng)請求一個jsp 頁面 回客戶端后,關(guān)閉此瀏覽器窗口,此時其內(nèi)存中的 sessionId也就隨之銷毀,在重新去請求sever 端的servlet 或jsp 時,會重新生成一個sessionId 給客戶端瀏覽器,并存在瀏覽內(nèi) 存中。
上面的理論在servlet 中測試都是成立的,下面談一下在struts 框架下進(jìn)行上面的測試時的不同的地方。
先簡要說下測試程序的流程:
客戶端請求index.do--->進(jìn)入server 端的IndexAction--->轉(zhuǎn)向
login.jsp 頁面----->請求login.do----->進(jìn)入server 端的LoginAction 。
首先說明:IndexAction 中沒有去產(chǎn)生session 對象,login.jsp 中設(shè)置。
(1)環(huán)境servlet jsp
在sevlet jsp測試跟蹤時,在index.do 進(jìn)入IndexAction 后轉(zhuǎn)向
login.jsp 時,此時瀏覽器內(nèi)存中是沒有會話 cookie的,那么在login.jsp 上請求login.do 進(jìn)入LoginAction 后,用request.getCookies()測試時,其 值是為null 的! 結(jié)果是吻合的,因為從始至終沒有產(chǎn)生過session 。
(2)環(huán)境struts jsp
在struts jsp測試跟蹤時,跟上面的流程一樣,開始想結(jié)果也應(yīng)該是一樣的,但經(jīng)過調(diào) 試后發(fā)現(xiàn)結(jié)果卻不是所想的那樣。在login.do 進(jìn)入 LoginActoin后用,用request.getCookies()測試時,發(fā)現(xiàn)其值不為null ,即使有name 和value ,開始很不理解,因 為根本就沒有創(chuàng)建過session 對象,哪來的會話cookie 值呢!但是結(jié)果有,那么想著此時瀏覽器內(nèi)存中也就應(yīng)該有會話cookie ,問題就在這里! 從哪里來的?
后來經(jīng)過仔細(xì)考慮后,想到struts 中的特點,我們自己寫的Action 類是繼承struts 的Action 的,而且之前是經(jīng)過struts 的中央控制器ActionServlet 來控制轉(zhuǎn)向的,所以我想肯定是在程序進(jìn)入我自己寫的IndexAction 之 前,struts 框架中的代碼肯定已經(jīng)創(chuàng)建了session 對象并已經(jīng)生成了sessionId 。于是就找到相關(guān)書籍查看了ActionServlet 工 作流程以及調(diào)用哪些類,看了之后果然在其中看到了HttpSession session = request.getSession();這樣一句話! 于是答案也就明白了。
大家知道struts 的ActionServlet 類中在接收到我們客戶端的請求(*.do)后(之前會做一系列初始化工作) ,并不是直接去處理我們的請求并調(diào)用相應(yīng)的Action(我們寫的如IndexAction) ,而是將處理工作交給RequestProcessor 類,其process 方法中會調(diào)用一系列的方法來完成相應(yīng)的請求處理和轉(zhuǎn)向操作。其中有一個方法引起了我的關(guān)注,就是processLocale()方法。
,Struts 框架:RequestProcess類中的processLocale()方法,原型如下: Java 代碼
1. protected void processLocale(HttpServletRequest request,
2. HttpServletResponse response) {
3. // Are we configured to select the Locale automatically?
4. if (!moduleConfig.getControllerConfig().getLocale())
5. // Has a Locale already been selected?
6. HttpSession session = request.getSession();
7.
8. if (session.getAttribute(Globals.LOCALE_KEY) != null)
9. // Use the Locale returned by the servlet container (if any)
10. Locale locale = request.getLocale();
11. if (locale != null) {
12. if (log.isDebugEnabled()) {
13. log.debug(" Setting user locale '" locale "'");
14. }
15. session.setAttribute(Globals.LOCALE_KEY, locale);
16. }
17.}
protected void processLocale(HttpServletRequest request,
HttpServletResponse response) { // Are we configured to select the Locale automatically? if (!moduleConfig.getControllerConfig().getLocale()) // Has a Locale already been selected? HttpSession session =
request.getSession(); if (session.getAttribute(Globals.LOCALE_KEY) != null) // Use the Locale returned by the servlet container (if any) Locale locale = request.getLocale(); if (locale != null) { if
(log.isDebugEnabled()) { log.debug(" Setting user locale '" locale "'"); } session.setAttribute(Globals.LOCALE_KEY, locale); }}
此類在struts-config.xml 配置文件中有對應(yīng)的配置項:< controller locale="true">< /controller>其缺省狀態(tài)locale 屬性的值為true ,也就會調(diào)用processLocale 方法,并在第一次請求時創(chuàng)建 session對象和生成sessionId 。但改為false 后,在第一次請求到達(dá)ActionServlet 后不會調(diào)用processLocale 方 法,也就不會生成session 對象了。
結(jié)果也就出來了,在struts 應(yīng)用中,*.do到達(dá)server 端后經(jīng)過
ActionServlet 后轉(zhuǎn)想我們自己寫的IndexAction 之前,< controller
locale="true">< /controller>(缺省狀態(tài)) 時,就已經(jīng)產(chǎn)生了session 對象和sessionId ,這是struts 框架類中生成的,即使我們在 IndexAction中寫上HttpSession session = request.getSession();其也是RequestProcess 類中的
,processLocale()方法生成的,此時其session 的isNew 也還是true ,因為還沒有返回客戶端,其是新創(chuàng)建的,那么按照上面的流程,當(dāng)在login.jsp 上通過login.do 進(jìn)入 LoginAction后,其request.getCookies()固然也就有值了! 并且其值是RequestProcess 類中的 processLocale()方法產(chǎn)生session 對象時生成的。
如果我們在struts-config.xml 中加上< controller locale="false">< /controller>時,此時如果再根據(jù)上面的流程來跟蹤程序,并在LoginAction 用request.getCookies()測試 時,其值是為null 的,當(dāng)然在IndexAction 寫上HttpSession session = request.getSession();時其是進(jìn)入IndexAction 時新創(chuàng)建的,isNew 也是true 。
應(yīng)用泛域名解析和java 的filter 實現(xiàn)對三級域名解析
關(guān)鍵字: 泛域名 java filter 域名解析
需求:
為每個在www.ecicc.oom 注冊商家提供一個三級域名, 三級域名直接指向商家自己的主頁面, 三級域名的組成方式為:注冊名稱.ecicc.com
商家又分為產(chǎn)業(yè)集群用戶和專業(yè)市場用戶, 這兩種用戶的應(yīng)用是不同的, 分別對應(yīng)企業(yè)展廳和專業(yè)網(wǎng)店。
對于產(chǎn)業(yè)集群用戶來說,企業(yè)展廳的連接構(gòu)造為:
網(wǎng)店暫未實現(xiàn)
設(shè)計:
通過泛域名解析,讓http://*.ecicc.com指向www.ecicc.com ,把服務(wù)器配置成支持泛域名。
通過java filter 獲取訪問的域名,截取域名中的三級域名。根據(jù)不同的三級域名重定向到相應(yīng)用戶。
如:用戶在地址欄中輸入:http://csic220.ecicc.com,用filter 截取csic220,重新定向為http://www.ecicc.com/web/csic220
程序代碼如下:
web.xml 文件
Java 代碼
1.
2.
3.
4.
5.
6.
7.
8.
java 文件
Java 代碼
1. package com.csic99.common.tools;
2.
3. import java.io.IOException;
4.
5. import javax.servlet.FilterChain;
6. import javax.servlet.FilterConfig;
7. import javax.servlet.ServletException;
8. import javax.servlet.ServletRequest;
9. import javax.servlet.ServletResponse;
10.
11.import javax.servlet.Filter;
12.import javax.servlet.http.HttpServletRequest;
13.import javax.servlet.http.HttpServletResponse;
14.
15.import org.springframework.context.support.AbstractApplicationContext;
16.import org.springframework.context.support.ClassPathXmlApplicationContext;
17.
18.import com.csic99.area.AcDirectionManager;
19.import com.csic99.product.UmUserManager;
20.import com.csic99.product.pojo.AcDirection;
21.import com.csic99.product.pojo.UmUser;
22./**
23. * 域名訪問站點的重新定位
24. * 必須在服務(wù)器上已經(jīng)配置好泛域名解析,
25. * 即http://*.ecicc.com是有效連接,它指定到www.ecicc.com
26. *
27. * @author zhx
28. *
29. */
30.public class URLFilter implements Filter{
31.
32. private static
33. AbstractApplicationContext appContext = new
34. ClassPathXmlApplicationContext("applicationContext-manager.xml");
35.
,36. public void destroy() {
37. // TODO Auto-generated method stub
38.
39. }
40.
41. public void doFilter(ServletRequest request, ServletResponse response,
42. FilterChain chain) throws IOException, ServletException {
43. HttpServletRequest httpServletRequest = (HttpServletRequest) request;
44. HttpServletResponse httpServletResponse = (HttpServletResponse) response;
45. //判斷是否是三級域,如http://csic220.ecicc.com
46. //獲取域名
47. String serverName = request.getServerName();
48. //判斷是否是三級域名
49. int end = serverName.indexOf("ecicc.com");
50. String userName = "";
51. //獲取用戶名
52. if(end!= -1&&end!=0){
53. userName = serverName.substring(0, end-1);
54. }else{
55. end = serverName.indexOf("csic99.com");
56. if(end!=-1&&end!=0){
57. userName = serverName.substring(0, end-1);
58. }
59. }
60. //用戶名不為空
61. if(userName!=null&&!"".equals(userName)){
62. //重定位的url
63. String url = "";
64. //獲取用戶管理對象
65. UmUserManager umUserManager =(UmUserManager) appContext.getBean("UmUserManager");
66. UmUser umUser = umUserManager.findUmUserByLoginName(userName);
67. if(umUser!=null){
68. AcDirectionManager acDirectionManager =
69. (AcDirectionManager)appContext.getBean("AcDirectionManager");
70. AcDirection acDirection =