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
欢迎大佬们指教!!