分布式下会话追踪[基于Cookie和Redis的实现]

本文探讨了在集群环境中负载均衡下会话管理的问题,详细分析了Session和Cookie的工作原理及区别,阐述了会话Cookie与持久Cookie的不同,并提供了通过UUID生成、设置过期时间和自定义参数解析器等技术手段解决会话保持问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 集群遇到的问题

从用户端来解释,就是当一个用户第一次访问被负载均衡代理到后端服务器A并登录后,服务器A上保留了用户的登录信息;当用户再次发送请求时,根据负载均衡策略可能被代理到后端不同的服务器,例如服务器B,由于这台服务器B没有用户的登录信息,所以导致用户需要重新登录。这对用户来说是不可忍受的。

二 .Session和Cookie的区别

1、session保存在服务器,客户端不知道其中的信息;cookie保存在客户端,服务器能够知道其中的信息。
2、session中保存的是对象,cookie中保存的是字符串。

三 .会话cookie和持久cookie的区别

如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
  如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。

代码实现:

生成UUID

public class UUIDUtil {
   public static String uuid() {
      return UUID.randomUUID().toString().replace("-", "");
   }
}

设置过期时间

public class MiaoshaUserKey extends BasePrefix{

   public static final int TOKEN_EXPIRE = 3600*24 * 2;
   private MiaoshaUserKey(int expireSeconds, String prefix) {
      super(expireSeconds, prefix);
   }
   public static MiaoshaUserKey token = new MiaoshaUserKey(TOKEN_EXPIRE, "tk");
}

客户端通过 token就能获取到用户信息

package com.imooc.miaosha.config;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.imooc.miaosha.domain.MiaoshaUser;
import com.imooc.miaosha.service.MiaoshaUserService;

@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

   @Autowired
   MiaoshaUserService userService;
   
   public boolean supportsParameter(MethodParameter parameter) {
      Class<?> clazz = parameter.getParameterType();
      return clazz==MiaoshaUser.class;
   }

   public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
         NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
      HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
      HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

      //从客户端获取
      String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN);
      //从cookie中获取
      String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN);
      //判空
      if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
         return null;
      }

      String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
      return userService.getByToken(response, token);
   }

   private String getCookieValue(HttpServletRequest request, String cookiName) {
      Cookie[]  cookies = request.getCookies();
      for(Cookie cookie : cookies) {
         if(cookie.getName().equals(cookiName)) {
            return cookie.getValue();
         }
      }
      return null;
   }

}

自定义参数解析器

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebConfig  extends WebMvcConfigurerAdapter{
   
   @Autowired
   UserArgumentResolver userArgumentResolver;
   
   @Override
   public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
      argumentResolvers.add(userArgumentResolver);
   }
}

通过redis获得信息

public MiaoshaUser getByToken(HttpServletResponse response, String token) {
   if(StringUtils.isEmpty(token)) {
      return null;
   }
   //從redis中获得数据
   MiaoshaUser user = redisService.get(MiaoshaUserKey.token, token, MiaoshaUser.class);
   //延长有效期
   if(user != null) {
      addCookie(response, token, user);
   }
   return user;
}

方法调用

private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
   redisService.set(MiaoshaUserKey.token, token, user);
   Cookie cookie = new Cookie(COOKI_NAME_TOKEN, token);
   cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
   cookie.setPath("/");
   response.addCookie(cookie);
} 

ok啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值