今天上午将一个数据存在一个方法中,再调用另外一个接口取出session中的值时,后端直接给我输出了一个空值:null。

我以为是配置啥的问题,捣鼓了一上午,心态崩了,还好,在网上寻求解决办法的时候,我才发现这是由前后端分离造成的。话不多说,直接上干货。

1.前后端分离中的Session的状态

前言:想珍惜生命的可以直接从第二部分看起,想把session弄得明明白白的建议从这里看起

1.1 Session是啥?

session你可以理解为就是一个小型数据库(有点牵强),它可以存放用户存入的键值对的值,但是session又将这些值存放在哪里呢?

有人可能会说是存放在服务器中,当然,存放在服务器中固然是对的,那它又存放在服务器的什么地方呢?

估计有不少人说是在内存中,其实,session真正的数据并不是存放在内存中的,就是本地存储,然后通过sessionId来标识键值对数据的唯一性(有点像redis了,但是信息的存放却是有本质性的区别)。

1.2 前后端分离中session的状态

话说以前前后端都在一起的时候,没有跨域的问题,session是可以确定的,但是在跨域的时候,我每次访问,都会像是新的一台主机访问我的服务器,就会造成session的新建,话说都新建一个session了,那我还能访问到原来的session数据吗?那是不可能的。

 那有啥办法吗?难道前后端分离中的session就是个摆设吗?还是我只能用浏览器的sessionStroger,接下来我们就来解决这个难题。

2.解决方法

2.1前端的解决方法

为啥我前段访问会让后端的java新开session,那还不是无法识别嘛

前端跨域访问后端接口, 在浏览器的安全策略下默认是不携带cookie的, 所以每次请求都开启了一次新的会话

所以我们就需要前端发送的数据中可以包含被后端识别。

Vue项目中,再main.js配置

axios.defaults.withCredentials = true;

 2.2后端如何处理

既然前端发送过来的数据已经携带了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("请求结束了");
    }
  1. preHandle方法:每次调用链接都会执行一次,里面写我们的逻辑代码
  2. postHandle方法:Controller层执行完后会执行
  3. afterCompletion方法:最后执行

在这里关于response.setHeader就不做过多介绍了,想了解的可以去看看浏览器里的网络传输

写完了自己的拦截器,我们需要注册到适配器中

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

3.测试

在我自己的项目中,我调用第一个方法,也就是图中的① ,存放键值对o:"123"

第二步:我要输出第一次的sessionID

第三步:我要输出第二次的访问的SessionID

第四步:我要取出session中指定的键值对

我们来看看结果

图中可以看出sessionID的值是一样的,在第二次访问时也能够取出键值为o的键值对。 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐