Redis+tomcat8.5+nginx实现session共享 window7版[2020.11.10]

所有配置一步到位,建议大家先配置Nginx负载均衡,再用Redis进行session共享

1.下载软件

2.软件配置

3.测试


1.下载软件及安装(Nginx、Redis、tomcat8.5、RedisManager)

  1.1 nginx下载(主要作用为负载均衡)

   下载1.18.0版本(稳定版)即可

nginx官方下载地址
在这里插入图片描述

1.2 redis下载

  redis官方下载链接

   本人下载的是Redis-x64-5.0.9(我的电脑是64位的,这个影响不大)

在这里插入图片描述


1.3 tomcat8.5下载

  tomcat8.5官方下载地址

  我的电脑是64位的

在这里插入图片描述


  1.3.1tomcat下lib包下载(用于Redis)

  这个地方需要注意的是版本冲突问题,目前这个测试过是没有问题的

   1.3.1.1 在github官网下载manager

   tomcat8.5-redis-session-manager.jar下载(github.com)

    1.1.1.2在阿里云下载jedis和commons-pool2

   阿里云仓库链接

※※※ *需要注意不要在阿里云下载 tomcat-redis-session-manager-2.0.0.jar*
※※※ *需要注意不要在阿里云下载 tomcat-redis-session-manager-2.0.0.jar*
※※※ *需要注意不要在阿里云下载 tomcat-redis-session-manager-2.0.0.jar*

  tomcat7用阿里云的jar包是没问题的,tomcat8.5用这个jar包会提示
classNotFoundException:XXX.XXX.XXX.LifecycleSupport.class

在这里插入图片描述


1.4RedisDeskTopManager(非必须下载)

  由于官网是付费的,这里就不贴下载链接了,目前是用来验证本地的Redis端口和密码能ping通(一般没啥问题),以后可能会有session免登陆,用来观察session的。


2.配置

2.1Redis配置

 redis安装,傻瓜式安装即可。
 关于配置文件,网上有很多文章,2种设置密码的方法。(一定要设置密码,不然可能会报错,最基本的错误是 ERR Client sent AUTH, but no password is set)

第一种方法
 一开始redis是默认不需要密码,如果想要设置密码,可以进入redis.windows.conf文件下找到requirepass,删除前面的#号,在其后面便可以设置密码,我这里设成了abc。
在这里插入图片描述

右键redis-server.exe 创建快捷方式 然后右键快捷方式 目标里 后面直接写 redis.windows.conf,这样直接打开快捷方式会自动加载配置文件 包括密码 IP地址(jedis.jar默认的是localhost redis配置文件默认的是127.0.0.1 2个都可以)
在这里插入图片描述


第二种方法:直接打开redis-server.exe(亲测有效,不实用)
关于密码参考原文copyBy https://www.cnblogs.com/tenny-peng/p/11543440.html
直接打开redis-server.exe,再打开redis-cli.exe(顺序不要反了),在客户端使用config get requirepass命令查看密码

>config get requirepass
1)"requirepass"
2)""    //默认空

客户端使用config set requirepass yourpassword命令设置密码

>config set requirepass abc
>OK

使用auth password验证密码

>auth abc
>OK
>config get requirepass
1)"requirepass"
2)"abc"

到此,密码设置完毕

此时一定不要关闭服务端,关闭会导致设置好的密码失效

一旦设置密码,必须先验证通过密码,否则所有操作不可用

>config get requirepass
(error)NOAUTH Authentication required

2.2 tomcat8.5配置(以端口8081、8082为例)

  需要更改的配置文件
   1.conf/server.xml
   2.conf/content.xml
   3.lib
   4. 更改root/index.jsp

   2.2.1.conf/server.xml 首先将下载好的tomcat安装,安装的时候端口设为8081
 在将安装的文件复制一份到当前文件夹,改好名字方便区分

在这里插入图片描述


更改conf/server.xml 启动端口(默认8080,3个端口都改肯定是一点问题都没有的)

<Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
 <Connector port="8082" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
  2.2.2.conf/content.xml

关于这块的配置网上有很多,但是都是关于Linux系统,由于我是window7所以总是报错,这里就贴出完整代码(请将密码改为之前设定的)

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
--><!-- The contents of this file will be loaded for each web application --><Context>

    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <!--<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> -->
	<Valve className="com.s.tomcat.redissessions.RedisSessionHandlerValve"/>
	<Manager className="com.s.tomcat.redissessions.RedisSessionManager" 
	database="0" 
	host="127.0.0.1" 
	maxInactiveInterval="120"
	password="abc" 
	port="6379"/>

			  
	
		
    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
</Context>

 database:默认是0
 host:如果reidis在本机,可以写127.0.0.1 、localhost或者192.168.10.XX(本机IP地址)如果是服务器,那就改成redis所在的服务器地址,有的时候不是代码错了,而是连接没通,本地CMD pingIP试试是否能ping通。
(注意:如果改成IP形式的,就需要在redis.windows.conf 文件将大概在56行的127.0.0.1 注释掉,换行 写上redis所在电脑的ip)
在这里插入图片描述

 maxInactiveInterval:一个失效时间,默认60s(不太确定具体的意思,但是不影响,不用改)
 password:之前设置好的密码,我这里是abc
 port:默认端口号6379,安装的时候一直下一步就是这个。


需要注意的几点:

1.我给<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>做了注释操作
2.网上有很多的关于value标签和Manager标签,出现最多的就是
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve"/>
启动tomcat就会报错,主要是jar包Class路径不对
在这里插入图片描述

推荐大家下载一个JDGui,用来解析jar包的,解析之后就会看到jar包路径,对比自己写配置是否出错
在这里插入图片描述
3.jedis版本(报错问题)
版本不对会导致出现java.lang.NoClassDefFoundError: redis/clients/jedis/JedisPoolConfig的错误。


 2.2.3.lib文件夹下放入下载好的3个jar包
在这里插入图片描述


 2.2.4.更改root/index.jsp(主要是用来测试进的是哪个端口的tomcat)

简单的写一个登录页面,因为没有后台,账号密码写死即可,写出端口号

<h1>tomcat 8081</h1>

复制到另外一个tomcat改成tomcat8082用以区分。
(我这里引用了一个jquery.min.jar,同级目录建一个js文件夹引入jar包即可)

再写一个登录之后的用户中心页面。
请记住这个端口号:8015 这个就是Nginx的自定义端口(默认是80)
window.location.href=“http://localhost:8015/userCenterView.jsp”;

<%--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--%>
<%@ page session="false" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy");
request.setAttribute("year", sdf.format(new java.util.Date()));
request.setAttribute("tomcatUrl", "https://tomcat.apache.org/");
request.setAttribute("tomcatDocUrl", "/docs/");
request.setAttribute("tomcatExamplesUrl", "/examples/");
%>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title><%=request.getServletContext().getServerInfo() %></title>
        <link href="favicon.ico" rel="icon" type="image/x-icon" />
        <link href="favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <link href="tomcat.css" rel="stylesheet" type="text/css" />
    </head>
<script src="js/jquery.min.js"></script>
		<style type="text/css">
		#biankuang{
			margin-left: 20%;
			margin-top: 300px;
			text-align: center;
			height:200px;
			border: 1px solid black;
			
			width: 350px;
		}	
		#account,#password{
			height:20px;
			width: 150px;
		}
		</style>
		<script type="text/javascript">
		function Submit(){
			var userName = $("#account").val();
			var userPwd = $("#password").val();
			if((userName=="123")&&(userPwd=="312")){
				window.location.href="http://localhost:8015/userCenterView.jsp";
			}else{
						window.reload();
					}
		}
		</script>
    <body>
        <div id="wrapper">
            <div id="navigation" class="curved container">
                <span id="nav-home"><a href="${tomcatUrl}">Home</a></span>
                <span id="nav-hosts"><a href="${tomcatDocUrl}">Documentation</a></span>
                <span id="nav-config"><a href="${tomcatDocUrl}config/">Configuration</a></span>
                <span id="nav-examples"><a href="${tomcatExamplesUrl}">Examples</a></span>
                <span id="nav-wiki"><a href="https://wiki.apache.org/tomcat/FrontPage">Wiki</a></span>
                <span id="nav-lists"><a href="${tomcatUrl}lists.html">Mailing Lists</a></span>
                <span id="nav-help"><a href="${tomcatUrl}findhelp.html">Find Help</a></span>
                <br class="separator" />
            </div>
            <div id="asf-box">
                <h1>${pageContext.servletContext.serverInfo}</h1>
            </div>
            <div id="upper" class="curved container">
                <div id="congrats" class="curved container">
					<h1>tomcat 8081</h1>
					Session Id:<%=request.getSession().getId()%>
                    <h2>If you're seeing this, you've successfully installed Tomcat. Congratulations!</h2>
                </div>
				<div id ="biankuang">
			<form onsubmit="return false" action="##">
						<h2>Tomcat1用户登录</h2>					
				账号:<input id ="account"  name ="userName"/>
				<br />
				<br />
				密码:<input id ="password" name ="userPwd" />
				<br />
				<br />
				<input type="button" value="登录" onclick="Submit()" />
			</form>	
		</div>
                
    </body>

</html>


新增用户中心页面userCenterView.jsp(与index.jsp同级即可)
同样的复制+更改名字8082

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@page isELIgnored="false" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<script src="js/jquery.min.js"></script>
		<script type="text/javascript">
		</script>
		<style>
			#userCenter{
				text-align: center;
				height: 180px;
				width: 400px;
				margin-top: 20%;
				margin-left: 40%;
				border: 1px solid #000000;
			}
		</style>
	<body>
		
		<div  id="userCenter">
			<h2>Tomcat1用户中心8081</h2>
			SessionId:<%=request.getSession().getId()%>
			<h5>欢迎登录</h5>
			
			
			</div>
	</body>
</html>

至此,tomcat8.5配置完毕,途中可能还有会其他问题,可以去看日志文件 logs/catalina.日期.log,配置好一定要运行一下bat文件确认tomcat是否可以正常启动


2.3Nginx负载均衡配置

2.3.1 {Nginx文件}/conf/

在这里插入图片描述


分割线


部分代码

upstream tomcatServer {
		server 192.168.10.XXX:8081;
		server 192.168.10.XXX:8082;
	}
    server {
        listen       8015;
        server_name  localhost;
		location  / {
		index	index.jsp index.html; 
		proxy_pass http://tomcatServer;
		proxy_set_header Host $host;
		#proxy_set_header X-Real-IP $remote_addr;
		#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
需要注意的是:这里listen端口号就是之前tomcat配置的端口号

至此,所有的配置文件已全部搞定!


 3.测试(尽量按照顺序就行)

  3.1 打开redis,设置好密码,测试可用即可(可以往上翻,有步骤)
  3.2 打开2个tomcat8.5 打开tomcat8.5/bin/startup.bat,确认成功开启无报错
  3.3 进入到ngine.exe目录 路径上cmd进入黑窗户,输入start nginx.exe,屏幕会闪一下,启动成功
  3.4 在网址上输入localhost:8015会轮询看到tomcat8081和tomcat8082字样,并且sessionID相同(刷新页面即可进行轮询)
  3.5 当进入tomcat8081的登录界面时,把tomcat8081的tomcat关掉,发现就会进入tomcat8082的userCenter里,可以试一下。
  需要注意的是当关掉tomcat其中一个时,nginx会认为这个服务器已经宕机,不会再进行分配,即使重新启动此服务器,此时只需要在当前黑窗户(nginx.exe目录)输入 nginx -s reload 即可将重启的服务器添加进去

地方

3.2关于服务器测试

1.与本地差别不大,主要是注意tomcat中content.xml中host地址要写成redis所在的服务器
2.tomcat 3个端口都要改 不然可能会有端口号冲突导致tomcat起不来
3.当所有配置都正确,在本机测试的8081,8082都可以,但是放到服务器无法正确跳转

 3.1首先确认 Nginx中 conf/nginx.conf配置文件 proxy_pass属性后面是否有proxy_set_header Host $host;
 3.2 更改 conf/nginx.conf中listen 端口号(原因是之前一直在本机测试,当加入服务器IP时,没有更新数据)
 3.3再确认防火墙是否拦截(ping服务器IP)或者百度一下进行操作.

4.确认tomcat版本和对应的JDK版本 (bin/version.bat

至此,session共享已经全部结束了。

如果你想做免登录操作或者maven,可以理性借鉴一下别的博主文章

https://www.cnblogs.com/zhrxidian/p/5491285.html
在远程服务器部署的时候需要注意的是 redis的配置文件中 redis.host要改成redis所在的电脑ip,并保证redis所在电脑中 redis.windows.conf 中 56行改成了redis所在电脑IP
<think>好的,我现在需要解决用户提到的“仅首次加载出现401错误,刷新后正常”的问题。根据用户提供的引用和之前的对话历史,我需要结合这些信息来找到合适的解决方案。首先,用户提到引用[1]中提到了Tomcat启动后请求重定向到ImageServlet时需要特定的入口reseponse,否则路径不正确。这可能与认证流程中的重定向路径配置有关,导致首次请求路径不完整,从而触发401错误。 接着,引用[2]讨论了转发与重定向的区别,指出重定向后浏览器URL会变化,而转发不会。这可能意味着在认证流程中使用了重定向,导致首次请求时未能正确携带认证信息,而刷新后由于浏览器处理了重定向后的URL,携带了正确的凭证。 引用[3]涉及API接口的安全设计,包括API密钥、签名验证、防止重复提交等,但当前问题更偏向于前端认证流程,这部分可能关联性不大,但可以忽略。 引用[4]提到前端路由的实现,如Vue Router,这可能与前端路由守卫的时序问题有关,导致首次加载时路由守卫未正确等待认证完成就发起请求,从而触发401错误。结合用户之前的回答,问题可能出在Token获取和前端路由初始化的顺序上。 用户之前给出的解决方案包括检查认证凭证的携带时机、同步认证流程、Cookie存储机制验证、服务端会话管理增强和OAuth2.0优化。现在需要根据用户提供的引用进一步调整解决方案,特别是引用[1]和[2]中的重定向和路径问题,以及引用[4]中的前端路由时序。 可能的解决方案包括: 1. **检查重定向路径配置**:确保认证重定向的路径正确包含所需的入口参数(如reseponse),避免路径缺失导致401错误。例如,在Tomcat或后端配置中确保重定向URL完整。 2. **前端路由守卫优化**:确保在应用初始化时先获取Token,再初始化路由,避免路由守卫在Token未获取时发起请求。可能需要调整前端代码,将Token获取设为同步或使用async/await确保顺序。 3. **认证流程中的重定向处理**:检查认证流程中是否正确处理了重定向后的URL,确保首次请求时携带必要的认证信息。例如,在OAuth流程中是否遗漏了必要的参数,导致首次认证失败。 4. **Cookie和Session管理**:验证服务端是否正确设置Cookie,特别是在跨域或重定向场景下,确保Cookie被正确存储和携带。检查SameSite属性设置,避免因安全限制导致Cookie未发送。 5. **服务端会话初始化时机**:确认服务端是否在重定向后正确初始化了会话,避免首次请求时会话未创建,而刷新后由于Cookie存在会话得以恢复。 需要结合用户的具体情况,比如使用的是Tomcat、前端框架如Vue等,来调整解决方案。例如,引用[1]中的路径问题可能需要检查后端重定向配置,确保入口参数正确;引用[4]的前端路由问题可能需要调整初始化顺序。此外,用户提到的刷新后正常,说明认证凭证在刷新后被正确携带,因此重点在于首次请求时如何确保凭证及时发送。</think>#### 深度解决方案:首次加载401错误专项处理 根据引用[1]的重定向路径问题和引用[2]的转发/重定向特性,结合前端路由时序问题(引用[4]),以下是针对性解决方案: --- ### 一、核心问题定位 **首次请求未携带认证凭证的根本原因**: 1. **重定向路径缺失关键参数**(引用[1]问题复现) - 示例:正确路径应为 `http://localhost:8090/reseponse/ImageServlet`,但首次请求变成 `http://localhost:8090/ImageServlet` 2. **前端路由初始化与认证异步竞争**(引用[4]延伸) - 路由守卫在Token获取完成前已触发受保护路由请求 3. **服务端会话创建滞后** - 首次重定向时服务端未完成会话存储初始化(如Redis连接延迟) --- ### 二、分阶段解决方案 #### 阶段1:修复重定向路径完整性(引用[1]) ```java // 后端修正重定向路径(示例为Spring Boot) @GetMapping("/red") public void redirectWithEntry(HttpServletResponse response) throws IOException { // 强制添加入口路径参数 response.sendRedirect("/reseponse/ImageServlet?captcha=" + generateCaptcha()); } ``` **验证方法**: - 使用浏览器开发者工具检查首次请求的`Location`响应头是否为完整路径 - 确认路径包含`reseponse`入口标识[^1] #### 阶段2:前端路由时序控制(引用[4]) ```javascript // Vue Router优化方案 let isAuthChecked = false; router.beforeEach(async (to, from, next) => { if (!isAuthChecked) { // 阻塞路由直到完成认证检查 await checkAuth(); isAuthChecked = true; } if (to.meta.requiresAuth && !store.state.auth.token) { next('/login'); } else { next(); } }); async function checkAuth() { try { const token = await axios.get('/api/refresh-token', { withCredentials: true }); store.commit('SET_TOKEN', token); } catch (error) { console.error('自动认证失败'); } } ``` **关键点**: - 使用路由守卫的阻塞逻辑确保初始化完成 - 静默尝试刷新Token(需配合服务端`/refresh-token`接口) #### 阶段3:服务端会话预热(引用[2]延伸) ```nginx # Nginx预创建会话(示例配置) location /reseponse/ImageServlet { proxy_pass http://backend; # 强制创建会话 proxy_set_header Early-Session-Init "true"; } ``` ```java // 服务端会话预创建逻辑 if ("true".equals(request.getHeader("Early-Session-Init"))) { request.getSession(true); // 强制创建新会话 } ``` --- ### 三、进阶调试技巧 1. **网络时序分析**: ```shell # 使用curl模拟首次请求 curl -v http://localhost:8090/red \ -H "Accept: text/html" \ -H "Cookie: JSESSIONID=invalid" # 强制触发401流程 ``` - 检查响应头中的`Set-Cookie`和`Location`字段 2. **浏览器存储监控**: ```javascript // 在控制台实时监控存储变化 Object.defineProperty(window, 'localStorage', { get: () => ({ ...localStorage, getItem: (key) => { console.log('读取:', key); return localStorage[key]; }, setItem: (key, val) => { console.log('写入:', key, val); localStorage[key] = val; } }) }); ``` --- ### 四、防御性编程建议 1. **客户端**: ```typescript // 添加请求重试机制 axios.interceptors.response.use(null, async (error) => { if (error.response.status === 401 && !error.config._retry) { error.config._retry = true; await refreshToken(); return axios(error.config); } return Promise.reject(error); }); ``` 2. **服务端**: ```java // 添加会话存在性检查过滤器 public class SessionCheckFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { HttpServletRequest request = (HttpServletRequest) req; if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) { ((HttpServletResponse)res).sendError(401, "Session expired"); return; } chain.doFilter(req, res); } } ``` --- ### 典型问题对照验证表 | 现象 | 验证方法 | 预期修复效果 | |---------------------|----------------------------|--------------------------| | 路径缺少入口参数 | 抓包检查Location响应头 | 重定向URL包含reseponse | | 前端路由抢先发起请求 | 在router.beforeEach添加日志 | 认证检查先于受保护路由执行 | | Cookie未跨域携带 | 检查Set-Cookie的Domain属性 | 跨域请求自动携带认证Cookie | --- ### 相关问题 1. 如何通过Nginx日志分析401错误的具体原因? 2. 在微服务架构中如何实现全局会话一致性? 3. 前端如何实现无感Token刷新机制? [^1]: 引用自用户提供的Tomcat重定向路径问题描述 [^2]: 参考转发与重定向的特性差异分析 [^4]: 结合前端路由初始化时序问题进行的方案设计
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值