Tomcat实现多域名之间session共享

转载自:http://blog.sina.com.cn/s/blog_69a890b301015zc6.html

-----------------------------------以下是原文----------------------------------

最近启用二级域名后,面临一个主域名与二级域名之间 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.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";
  }

  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;
  }

  @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());
        }
      }
    }
  }

  public String toString() {
    return ("CrossSubdomainSessionValve[container=" + container.getName() + ']');
  }
}

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

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

重启 Tomcat ,Done !

 

引用自:http://blog.seanchang.me/tomcat-to-achieve-the-main-domain-name-session-sharing-between-subdomains.html
### 关于语言大模型微调的实际操作案例或教程 #### 大规模语言模型的微调概述 大规模预训练语言模型可以通过微调来适应特定的任务需求。这种方法利用了模型已经学到的语言表示能力,并针对具体应用场景进行优化[^1]。 #### 动态权重分配机制与MoE门控 一种有效的策略是在微调过程中引入动态权重分配机制,特别是基于混合专家(MoE)架构的设计。该方法能够通过注意力门控模块实现参数的部分更新,从而减少灾难性遗忘的风险并保持较高的泛化性能。例如,在医疗问答场景下,仅需调整少量专家参数即可完成领域知识的有效注入[^2]。 以下是MoE门控机制的一个简化版本伪代码示例: ```python import torch.nn as nn import torch.nn.functional as F class MoEGate(nn.Module): def __init__(self, hidden_size, num_experts): super(MoEGate, self).__init__() self.gate = nn.Linear(hidden_size, num_experts) def forward(self, x): weights = F.softmax(self.gate(x), dim=-1) expert_mask = torch.topk(weights, k=2)[1] # 选择Top2专家 return expert_mask, weights ``` #### 阿里Qwen系列大模型微调实践 对于实际应用中的任务定制化需求,阿里云提供了详细的Qwen系列大模型微调指南。这些资源涵盖了从环境搭建到模型部署的一整套流程,帮助开发者快速掌握如何根据自己的业务特点对大模型进行针对性改进[^3]。 下面是一个简单的微调脚本框架示意: ```python from transformers import AutoModelForCausalLM, AutoTokenizer # 加载预训练模型及其分词器 model_name_or_path = "your_model_checkpoint" tokenizer = AutoTokenizer.from_pretrained(model_name_or_path) model = AutoModelForCausalLM.from_pretrained(model_name_or_path) # 准备自定义数据集 train_dataset = [...] # 替换为您的训练样本列表 eval_dataset = [...] # 可选验证集合 def collate_fn(batch): """ 数据批处理函数 """ texts = [item["text"] for item in batch] labels = [item["label"] for item in batch] encodings = tokenizer(texts, padding=True, truncation=True, max_length=512, return_tensors="pt") encodings["labels"] = torch.tensor(labels).unsqueeze(-1) # 假设回归/分类任务 return encodings # 定义Trainer所需的组件 training_args = { 'output_dir': './results', 'num_train_epochs': 3, 'per_device_train_batch_size': 8, 'save_steps': 500, } trainer = CustomTrainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, data_collator=collate_fn, ) # 开始训练过程 trainer.train() ``` 上述代码片段展示了如何加载一个现有的因果语言模型(Causal LM),并通过`transformers`库提供的工具对其进行适配和训练。注意替换掉路径名以及准备适合自己项目的输入格式。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值