最近启用二级域名后,面临一个主域名与二级域名之间 session 不能共享的问题,带来的麻烦就是用户在主域名登陆,但由于二级域名 session 不能共享 ,因此无法进行登陆的操作,对一些功能有一些影响。

问题的原因如下
Tomcat 下,不同的二级域名,Session 默认是不共享的,因为 Cookie 名称为 JSESSIONID 的 Cookie
根域是默认是没设置的,访问不同的二级域名,其 Cookie 就重新生成,而 session 就是根据这个 Cookie
来生成的,所以在不同的二级域名下生成的 Session 也不一样。
找到了其原因,就可根据这个原因对 Tomcat 在生成 Session 时进行相应的修改。

快速解决方案1
在项目的/MET-INF/ 目录下创建一个 context.xml 文件,内容为:

1
2
<?xml version="1.0" encoding="UTF-8"?>
<Context useHttpOnly="true" sessionCookiePath="/" sessionCookieDomain=".XXXX.com" />

Done!

快速解决方案2:修改 Tomcat 的 server.xml 文件,内容为:

1
<Context path="" docBase="ROOT" reloadable="false" useHttpOnly="true" sessionCookiePath="/" sessionCookieDomain=".XXXX.com" />

Done!

以上两种方案的详细讲解见:http://tomcat.apache.org/tomcat-6.0-doc/config/context.html

快速解决方案3
:生成一个叫做 crossSubdomainSessionValve.jar 的文件,用的时候放在
Tomcat lib 目录下,然后修改 Tomcat server.xml 文件:

1
<Valve className="me.seanchang.CrossSubdomainSessionValve" />

原理:取代由 Tomcat 域产生的会话 cookie ,允许该会话 cookie
跨子域共享。

代码:

 
package me.seanchang;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger; import javax.servlet.ServletException;
import javax.servlet.http.Cookie; import org.apache.catalina.Globals;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.http.ServerCookie; public class CrossSubdomainSessionValve extends ValveBase {
private static Logger log = Logger.getLogger("CrossSubdomainSessionValve");
public CrossSubdomainSessionValve() {
super();
info = "me.seanchang.CrossSubdomainSessionValve/1.0";
} @Override
public void invoke(Request request, Response response) throws IOException,
ServletException {
// this will cause Request.doGetSession to create the session cookie if
// necessary
request.getSession(true); // replace any Tomcat-generated session cookies with our own
Cookie[] cookies = response.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i]; log.info("CrossSubdomainSessionValve: Cookie name is "
+ cookie.getName());
if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName()))
replaceCookie(request, response, cookie);
}
} // process the next valve
getNext().invoke(request, response);
} protected void replaceCookie(Request request, Response response, Cookie cookie) {
// copy the existing session cookie, but use a different domain
Cookie newCookie = new Cookie(cookie.getName(), cookie.getValue());
if (cookie.getPath() != null)
newCookie.setPath(cookie.getPath());
newCookie.setDomain(getCookieDomain(request));
newCookie.setMaxAge(cookie.getMaxAge());
newCookie.setVersion(cookie.getVersion());
if (cookie.getComment() != null)
newCookie.setComment(cookie.getComment());
newCookie.setSecure(cookie.getSecure()); // if the response has already been committed, our replacement strategy
// will have no effect
MimeHeaders headers = new MimeHeaders();
if (response.isCommitted()) log.info("CrossSubdomainSessionValve: response was already committed!");
// find the Set-Cookie header for the existing cookie and replace its
// value with new cookie
headers = response.getCoyoteResponse().getMimeHeaders();
for (int i = 0, size = headers.size(); i < size; i++) {
if (headers.getName(i).equals("Set-Cookie")) {
MessageBytes value = headers.getValue(i);
if (value.indexOf(cookie.getName()) >= 0) {
StringBuffer buffer = new StringBuffer();
ServerCookie
.appendCookieValue(buffer, newCookie.getVersion(),
newCookie.getName(), newCookie.getValue(),
newCookie.getPath(), newCookie.getDomain(),
newCookie.getComment(),
newCookie.getMaxAge(),
newCookie.getSecure(), true); log.info("CrossSubdomainSessionValve: old Set-Cookie value: "
+ value.toString());
log.info("CrossSubdomainSessionValve: new Set-Cookie value: "
+ buffer);
value.setString(buffer.toString());
}
}
}
} protected String getCookieDomain(Request request) {
String cookieDomain = request.getServerName();
String[] parts = cookieDomain.split("\\.");
if (parts.length >= 2)
cookieDomain = parts[parts.length - 2] + "."
+ parts[parts.length - 1];
return "." + cookieDomain;
} public String toString() turn ("CrossSubdomainSessionValve[container=" + container.getName() + ']');
}
}

将以上代码导出一个jar文件,放入 $CATALINA_HOME/lib 中,修改 $CATALINA_HOME/conf/server.xml 文件,加入

1
<Valve className="me.seanchang.CrossSubdomainSessionValve" />

重启 Tomcat ,Done !

Tomcat实现多域名之间session共享的更多相关文章

  1. Nginx+Tomcat+memcached负载均衡实现session共享

    http://blog.csdn.net/love_ubuntu/article/details/8464983 1.  安装各个软件不用说了. 2.  到tomcat的安装目录lib中,加入: me ...

  2. nginx+tomcat+redis的集群+session共享

    nginx+tomcat+redis的集群+session共享 环境准备 1.tomcat版本:tomcat7 tomcat下载及安装,目前很多好的资源和步骤,此处省略. 2.jdk版本:jdk1.7 ...

  3. nginx+tomcat+redis负载均衡及session共享

    概述 本文档是用来详细描述 nginx+tomcat+redis负载均衡实现session共享 所需软件及下载地址 软件名称 下载地址 功能说明 Nginx-v1.6.0 http://nginx.o ...

  4. Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享

    Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享 ============================= 蕃薯耀 2017年11月27日 http: ...

  5. haproxy+tomcat实现负载均衡以及session共享(linux centos7环境)

    一.安装HAProxy 1.进入home目录,下载最新haproxy安装包. cd /home wget http://haproxy.1wt.eu/download/1.4/src/haproxy- ...

  6. Thinkphp框架下(同服务器下)不同二级域名之间session互通共享设置

    在Thinkphp框架下根目录打开index.php 在头部加入如下代码即可: //入口文件 define('DOMAIN','abc.com');//abc.com换成自己的跟域名 //以下两行是为 ...

  7. nginx整合tomcat集群并做session共享----测试案例

    最近出于好奇心,研究了一下tomcat集群配置,并整合nginx,实现负载均衡,session共享,写篇记录,防止遗忘.---------菜鸡的自我修炼. 说明:博主采用一个web项目同时部署到两台t ...

  8. Tomcat集群环境下session共享方案 通过memcached 方法实现

    对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式:一种是把所有Ses ...

  9. 多服务器之间Session共享

    原理:多个服务器间想共享session,就相当于共享取多台主机上的一个变量,所以共享的思路就是让大家都能读取变量,实现的方法可以通过将session保存到专门的一个服务器上,所有服务器都去请求数据,也 ...

随机推荐

  1. Android指纹识别API讲解,让你有更好的用户体验

    我发现了一个比较怪的现象.在iPhone上使用十分普遍的指纹认证功能,在Android手机上却鲜有APP使用,我简单观察了一下,发现Android手机上基本上只有支付宝.微信和极少APP支持指纹认证功 ...

  2. 【Learning】矩阵树定理 Matrix-Tree

    矩阵树定理 Matrix Tree ​ 矩阵树定理主要用于图的生成树计数. 看到给出图求生成树的这类问题就大概要往这方面想了. 算法会根据图构造出一个特殊的基尔霍夫矩阵\(A\),接着根据矩阵树定理, ...

  3. Linux及安全实践四——ELF文件格式分析

    Linux及安全实践四——ELF文件格式分析 一.ELF文件格式概述 1. ELF:是一种对象文件的格式,用于定义不同类型的对象文件中都放了什么东西.以及都以什么样的格式去放这些东西. 二.分析一个E ...

  4. Android中Selector的用法(改变ListView和Button的默认背景)

    Android中的Selector的用法 http://blog.csdn.net/shakespeare001/article/details/7788400#comments Android中的S ...

  5. 解题:ZJOI 2013 K大数查询

    题面 树套树,权值线段树套序列线段树,每次在在权值线段树上的每棵子树上做区间加,查询的时候左右子树二分 本来想两个都动态开点的,这样能体现树套树在线的优越性.但是常数太大惹,所以外层直接固定建树了QA ...

  6. bzoj2300【HAOI2011】防线修建

    题目描述 近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了.可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于 ...

  7. 【数据结构】【CF1073D】 Berland Fair

    Description 给定 \(n\) 个商店,他们围成一个圆圈,按照顺时针从 \(1\) 到 \(n\) 编号.你有 \(T\) 元钱,从 \(1\) 号点开始按照顺时针方向走,每到一个商店,只要 ...

  8. python函数:基础函数调用整理

    声明:以下链接和描述据来自于网络,很多都是来自菜鸟教程 一.字符串 str python字符串格式化符号: %c 格式化字符及其ASCII码  %s 格式化字符串 %d 格式化整数 函数 描述 需要掌 ...

  9. python基础之02列表/元组/字典/set集合

    python中内置的数据类型有列表(list)元组(tuple)字典(directory). 1 list list是一种可变的有序的集合.来看一个list实例: #第一种方法: >>&g ...

  10. Hadoop部署方式-本地模式(Local (Standalone) Mode)

    Hadoop部署方式-本地模式(Local (Standalone) Mode) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Hadoop总共有三种运行方式.本地模式(Local ...