分布式会话:聊聊cookie 和 session

cookie:

1. 首先说http :http本质是无状态的, 服务器不能识别浏览器,如何让他记住,通过cookie

2. httpcookie : 是服务器发送到浏览器,并保存在本地的一小块数据,浏览器下次向同一服务器请求的时候,会携带cookie过去,相当于令牌

 1.第一次浏览器访问服务起的时候,没有cookie
 2.由服务器创建cookie,通过响应头的形式 set-cookie发给浏览器
 3. 浏览器接受到服务器的cookie信息,存到本地硬盘上
 4. 下次访问服务器的时候,把本地保存的cookie发给服务器
 5,服务器读取并且进行操作

3. Cookie 本身是一些键和值,而且键和值都是字符串类型,同时cookie 用于存放用户信息也不太好,而且cookie的大小限制为4k, cookie保存在内存里,如果浏览器关了,就没了,最好设置时间,保存到硬盘,如果用户在浏览器设置禁用我们的cookie,我们就无法在浏览器存储我们的cookie数据了

session:

1. session 是java ee 的标准,而cookie是http的标准

2. Session 数据是保存在服务端,Session 键是字符串类型,值是 Object 类型,存任何类型

分布式部署session 会有问题:

 每台服务器存有session,浏览器不是直接的访问服务器,而是访问Nginx,通过反向代理服务器,分发请求,各服务器之间的session不能共享

解决办法: 
 1. 设置负载均衡分配的策略 , 
 2.  粘性session,同一个ip地址访问,Nginx将请求发送到同一个服务器,每次都是通过一个服务器处理,缺点,难以保证负载均衡
 3. 同步session,把session同步给其他的服务器,服务器性能降低,产生耦合
 4. 共享session,专门弄一台服务器处理session,其他服务器来找这台,缺点: 单体,万一挂了,其他的服务器都无法工作

分布式会话: 

不管是集群,还是微服务,用户会话一旦存入redis,在任何的节点都可以获取,需要把用户的会话信息做相应的设置,把cookie和后端的token接合起来存起来

例如:在登录功能里面需要保存我们的用户的token和uid

1. 在用户登录状态后,通过UUID生成一个随机的token,然后以token+userid组成一个key,把token的值存入redis,同时以info+userid组成一个key,以user信息为值存入redis

// 生成用户的token进行保存放入的Redis
String uToken = UUID.randomUUID().toString();
redis.set(REDIS_USER_TOKEN + ":" + user.getId(),uToken);

// 和以前单体项目差不多,相当于在httpsession里面保存一个用户信息和token
redis.set(REDIS_USER_INFO + ":" + user.getId(), JsonUtils.objectToJson(user));

2.  值为string类型的redis只能保存string类型,而上面代码,我们是通过一个json工具类将user类型的object对象转为json字符串存入redis,工具类如下所示

public class JsonUtils {

    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
    	try {
			String string = MAPPER.writeValueAsString(data);
			return string;
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    /**
     * 将json结果集转化为对象
     * 
     * @param jsonData json数据
     * @param beanType 对象中的object类型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json数据转换成pojo对象list
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
    	JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
    	try {
    		List<T> list = MAPPER.readValue(jsonData, javaType);
    		return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
    	
    	return null;
    }
    
}

3. 用户的这个token和id也要保存到前端的cookie里面,保留用户的基本信息,后端可以对当前的请求进行校验,获得当前的用户的相关信息和会话,编写在cookie里面进行设置的方法

   /**
     *
     * @param request       设置cookie必须要这两个参数
     * @param response
     * @param cookieName    Cookie 本身是一些键和值,而且键和值都是字符串类型
     * @param cookieValue   Cookie 本身是一些键和值,而且键和值都是字符串类型
     * @param maxAge        设置cookie的存活时间
     */
    public void setCookie(HttpServletRequest request,
                          HttpServletResponse response,
                          String cookieName,
                          String cookieValue,
                          Integer maxAge){
        try {
            cookieValue = URLEncoder.encode(cookieValue, "utf-8");
            setCookieValue(request,response,cookieName,cookieValue,maxAge);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public void setCookieValue(HttpServletRequest request,
                          HttpServletResponse response,
                          String cookieName,
                          String cookieValue,
                          Integer maxAge){
            Cookie cookie = new Cookie(cookieName, cookieValue);
            cookie.setMaxAge(maxAge);
            // 设置域: 资源属性和常量绑定,自定义写入配置文件
            cookie.setDomain(DOMAIN_NAME);
            // 设置cookie在哪些url下,我们设置整个项目有效
            cookie.setPath("/");

            // cookie最终是要设置到响应里面去的,发送给客户端浏览器查看
            response.addCookie(cookie);
        }

4.  有了上面的方法,就可以在我们的cookie里面保存uid和token了

setCookie(request,response,"utoken",uToken,COOKIE_MONTH);
setCookie(request,response,"uid",user.getId(),COOKIE_MONTH);

5. 用户退出登录后,就需要清除我们的cookie信息和redis里面的token

// 0. 从redis清除用户token ,token是验证用户有没有登录过 , 用户基本信息不需要删除
redis.del(REDIS_USER_TOKEN + ":" + userId);

// 1. cookie清除,cookie没有删除,重新设置过期时间为0 自动删除
setCookie(request,response,"utoken","",COOKIE_DELETE);
setCookie(request,response,"uid","",COOKIE_DELETE);


// 备注:COOKIE_DELETE = 0

欢迎大佬们指教!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值