今天上午将一个数据存在一个方法中,再调用另外一个接口取出session中的值时,后端直接给我输出了一个空值:null。
我以为是配置啥的问题,捣鼓了一上午,心态崩了,还好,在网上寻求解决办法的时候,我才发现这是由前后端分离造成的。话不多说,直接上干货。
前言:想珍惜生命的可以直接从第二部分看起,想把session弄得明明白白的建议从这里看起。
session你可以理解为就是一个小型数据库(有点牵强),它可以存放用户存入的键值对的值,但是session又将这些值存放在哪里呢?
有人可能会说是存放在服务器中,当然,存放在服务器中固然是对的,那它又存放在服务器的什么地方呢?
估计有不少人说是在内存中,其实,session真正的数据并不是存放在内存中的,就是本地存储,然后通过sessionId来标识键值对数据的唯一性(有点像redis了,但是信息的存放却是有本质性的区别)。
话说以前前后端都在一起的时候,没有跨域的问题,session是可以确定的,但是在跨域的时候,我每次访问,都会像是新的一台主机访问我的服务器,就会造成session的新建,话说都新建一个session了,那我还能访问到原来的session数据吗?那是不可能的。
那有啥办法吗?难道前后端分离中的session就是个摆设吗?还是我只能用浏览器的sessionStroger,接下来我们就来解决这个难题。
为啥我前段访问会让后端的java新开session,那还不是无法识别嘛
前端跨域访问后端接口, 在浏览器的安全策略下默认是不携带cookie的, 所以每次请求都开启了一次新的会话
所以我们就需要前端发送的数据中可以包含被后端识别。
Vue项目中,再main.js配置
axios.defaults.withCredentials = true;
既然前端发送过来的数据已经携带了cookie,那么我们怎样识别出来呢?
如同我们上面说的,每发送一次链接,后端都会以为是一台新的主机来访问,所以我们就需要针对每一次请求来进行处理。
这里我们就需要用到拦截器
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("经过了拦截器");
response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));//支持跨域请求
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");//是否支持cookie跨域
response.setHeader("Access-Control-Allow-Headers", "Authorization,Origin, X-Requested-With, Content-Type, Accept,Access-Token");//Origin, X-Requested-With, Content-Type, Accept,Access-Token
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("controller 执行完了");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("我获取到了一个返回的结果:"+response);
System.out.println("请求结束了");
}
preHandle方法:每次调用链接都会执行一次,里面写我们的逻辑代码
postHandle方法:Controller层执行完后会执行
afterCompletion方法:最后执行
在这里关于response.setHeader就不做过多介绍了,想了解的可以去看看浏览器里的网络传输
写完了自己的拦截器,我们需要注册到适配器中
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
在我自己的项目中,我调用第一个方法,也就是图中的① ,存放键值对o:"123"
第二步:我要输出第一次的sessionID
第三步:我要输出第二次的访问的SessionID
第四步:我要取出session中指定的键值对
我们来看看结果
图中可以看出sessionID的值是一样的,在第二次访问时也能够取出键值为o的键值对。