在前后端分离中由于跨域导致的springmvc中的controller类中的session值不一致或者为null的情况分析处理

2022-07-13 10:38:34

异常

在前后端分离项目中,前端采用Ajax提交数据到后端,而后端采用SSM来接收传过去的参数数据。

例如下:

后台访问接口的地址:

前端浏览页面的地址:

可以发现两个地址的端口号是不一样的,后端是8484,前端是8848,这就会产生跨域问题,即前端通过Ajax发送的请求,后端无法接收到,自然也无法响应前台,前台也无法获取到后端的资源。

一般情况下,前后端的代码一起开发,如都在IDEA中写的,运行tomcat就不会产生跨域问题,例如:

那么它们不同controller之间的session设置后,是可以共享的,是同一个sessionID

可以查看下sessionID发现确实是同一个

下面就说下前后端分离导致的跨域问题,就是前端和后端分别开发,通过接口交互。

这里前端使用的是HBuilderX

后端仍然是IDEA

前端通过HBuilderX内置浏览器来查看页面效果,同时与后端进行交互。

二者的浏览器地址分别为:

前端:http://127.0.0.1:8848/Demo2/index2.html

后端:http://localhost:8484/ssm_war/

可以发现两个地址的端口号不同,这就会产生跨域问题。

只要出现上面红框的错误,就是跨域问题。

SSM提供了解决跨域问题的方案,通过@CrossOrigin注解来解决,在每个Controller类上添加@CrossOrigin注解即可前端解决跨域问题。

再次点击页面的“设置session”按钮,发现没有跨域报错了,但是点击”获取session“按钮,会提示获取session失败,为null值。

解决了跨域问题后,这才来到了本次问题的核心。

观察两次操作的sessionID,发现并不一样

学习web的时候知道session其实底层是基于cookie的。

出现了这个问题,在前后端开发的时候,就不能在不同Controller类中共享session中的数据,这个问题的发现是在登录后需要将用户信息保存在session中,然后在不同controller类中访问。

下面是解决这个问题:

第一步,在前端的ajax请求中添加如下红框内的代码

vue中axios配置该字段的代码如下:

第二步:springmvc的@CrossOrigin注解支持

现在就可以在不同的controller类中访问session中共享的数据了,因为都是访问的是同一个session对象。

默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等),这句话的意思就是跨域时,默认是作跨域请求时,不会携带cookie参数,而我们知道session是基于cookie的,如果不携带cookie,那么session自然也无法作为,所以就需要xhrFields: {withCredentials: true}这段代码来设置,使得跨域请求时携带cookie,同时,后端的springmvc代码也需要同意,所以@CrossOrigin(origins = "*",allowCredentials = "true")这段代码就表示解决跨域的同时允许接收cookie等数据。

下面通过一个实例来验证上面这段话。

index3_1.html在HBuilderX的内置浏览器中作跨域请求

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"/>
		<script src="jquery.min.js"></script>
	</head>
	<body>
    <button type="button" id="btn1">设置cookie</button>
    <button type="button" id="btn2">获取cookie</button>
    <script>
      $("#btn1").click(function(){
        $.ajax({
          url: 'http://localhost:8484/ssm_war/setCookie',
          type: 'post',
          data: {"username": "zhangsan"},
          success: function(resp){
            alert(resp)
          }
        })
      })
      $("#btn2").click(function(){
        $.ajax({
          url: 'http://localhost:8484/ssm_war/getCookie',
          type: 'get',
          success: function(resp){
           alert(resp)
         }
        })
      })
    </script>
	</body>
</html>

TestController3.java解决跨域请求,同时设置cookie和获取cookie

@CrossOrigin
@Controller
public class TestController3 {
    // 测试使用
    @RequestMapping("/setCookie")
    @ResponseBody
    public String setCookie(HttpServletResponse response){
        Cookie cookie=new Cookie("myCookie","我的cookie");
        response.addCookie(cookie);
        return "设置cookie成功!";
    }

    @RequestMapping("getCookie")
    @ResponseBody
    public String getCookie(HttpServletRequest request){
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName()+"="+cookie.getValue());
        }
        return "获取cookie";
    }
}

然后点击“设置cookie”按钮,后台会创建一个名为"myCookie"的cookie成功

点击“获取cookie”按钮,就会报错了

定位到后台代码是

解决其实就是上面的xhrFields: {withCredentials: true}配置,允许跨域请求携带cookie等数据。

后端

再次运行就会发现获取cookie成功

后端控制台也会打印cookie数据,同样有JSESSIONID,也就说明了session能够使用了。

以上就是关于本次问题的探讨。

本次项目的源码:GitHub的Demo

  • 作者:二木成林
  • 原文链接:https://blog.csdn.net/cnds123321/article/details/113004982
    更新时间:2022-07-13 10:38:34