异常
在前后端分离项目中,前端采用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