报错:
Access to XMLHttpRequest at 'http://localhost:8080/SpringBootServer/testfile' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
- 诱因
两天研究springboot,因为刚接触没多久springboot,所以遇到了一堆的问题,首先这个springboot我这里建立的是没有web.xml配置文件的,所以在设置过滤器的时候,不知道在哪里设置,导致网上查的一堆在web.xml通过filter设置的过滤器解决跨域问题,我这里都没有用,还有写一写配置文件或者是写一个类文件,配置文件没有,类文件没有用。于是我找了一个晚上,终于找到了解决的办法以及原因,详细如下。 - 前台的代码块如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--我这里使用的是3.4.0的js-->
<script type="text/JAVAscript" src="js/jquery-3.4.0.js" ></script>
<script type="text/JavaScript" src="js/jquery-3.4.0.min.js" ></script>
</head>
<body>
<!--一个简单的form表单,测试通过button点击事件,ajax来进行post方式的携带参数发送请求,所以这里没必要写submit和method-->
<form method="post">
账号:<input type="text" name="userCode" id="userCode"/><br/>
密码:<input type="password" name="userPassword" id="userPassword"/><br/>
<input type="button" value="登录" id="button"/>
</form>
</body>
</html>
<script type="text/javascript">
$button = $("#button")
/*点击按钮的时候给一个点击事件*/
$button.click(function(){
/*得到输入框内的值*/
var userCode = $("#userCode").val();
var userPassword = $("#userPassword").val();
$.ajax({
type:"post",
/*你要往哪里发送请求*/
url:"http://localhost:8080/doLogin",
data:{
"userCode":userCode,
"userPassword":userPassword
},
/*设置xhrFields: {withCredentials: true},为true时。
发送Ajax时,Request header中便会带上 Cookie 信息,否则不携带Cookie
测试结果如果不写或者不为true的话,后台的session.getid()不是同一个*/
xhrFields: {withCredentials: true},
/*crossDomain: true。发送Ajax时,Request header 中会包含跨域的额外信息,
但不会含cookie。*/
crossDomain: true,
dataType:"text",
success:function(result){
/*如果成功的话弹一下后台返回的值并且跳转页面到登录成功的页面*/
alert(result)
window.location.href="index.html";
},
error:function(){
alert("出错了")
}
});
})
</script>
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
- 后台代码块如下,注:这个是springboot项目
package cn.test.controller;
import cn.test.pojo.SmbmsRole;
import cn.test.pojo.SmbmsUser;
import cn.test.service.UserService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.List;
/**
* @RestController 声明这个是个controller并且返回的数据类型可以为json
* @CrossOrigin springboot中支持跨域的注解
* */
@RestController
@CrossOrigin
public class UserController {
/**
* @Resource 自动注入的注解
* */
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private UserService userService;
/**
* 进行登录验证的方法
* 接受ajax传递过来的参数
* 这里还需要session,response,request来进行一些跨域的设置
* 亲测,最终成功运行并且结果返回为true
* */
@RequestMApping("/doLogin")
public String doLogin(@RequestParam("userCode")String userCode,
@RequestParam("userPassword")String userPassword,
HttpSession session, HttpServletResponse response, HttpServletRequest request){ /**
* 测试的输出一下发送请求的域名
* 最主要的解决问题的代码来了,我这里为了尽量阐述明白查阅了好多资料,写了大量的注释,希望大家可以看的更明白一点
* */
System.out.println(request.getHeader("Origin"));
/**
*在响应 header 中设置 ‘*’ 来允许来自所有域的跨域请求访问
* 较灵活的设置方式 允许这个域名进行访问,request.getHeader("Origin"),通过request.getHeader('Origin')来得到访问来源的域名
* 这行代码很重要,必须写
* */
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
/**
* 首部字段 Access-Control-Allow-Headers 表明服务器允许请求中携带字段 X-PINGOTHER 与 Content-Type。
* Access-Control-Allow-Headers 的值为逗号分割的列表
* 这个可以不写,写这个就是表明服务器允许请求中携带的字段
* */
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
/**
* 前台ajax发送的请求中对应客户端的 xhrFields.withCredentials: true 参数
* 服务器端通过在响应 header 中设置 Access-Control-Allow-Credentials = true 来运行客户端携带证书式访问。
* 通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie。这里需要注意的是:
* 服务器端 Access-Control-Allow-Credentials = true时,参数Access-Control-Allow-Origin 的值不能为 '*'
* 这是因为请求的首部中携带了 Cookie 信息
* 如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。
* 这行代码也必须加
* */
response.setHeader("Access-Control-Allow-Credentials", "true");
System.out.println(session.getId());
System.out.println("进入了登录验证的方法");
SmbmsUser smbmsUser = userService.getUser(userCode,userPassword); session.setAttribute("smbmsUser",smbmsUser);
if(smbmsUser!=null){
return "true";
}else{
return "false";
} } /**
* 增加数据的控制层方法
* 这里也需要使用到session,response来进行一系列的设置
* */
@RequestMapping(value = "/add",method = RequestMethod.POST)
public Object addSmbmsRole( SmbmsRole smbmsRole,HttpSession session,HttpServletResponse response,
HttpServletRequest request){ response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Credentials", "true");
System.out.println("进入增加数据的方法");
System.out.println(session.getId());
System.out.println(((SmbmsUser)session.getAttribute("smbmsUser")).getCreatedBy());
smbmsRole.setCreatedBy(((SmbmsUser)session.getAttribute("smbmsUser")).getCreatedBy());
smbmsRole.setCreationDate(new Date()); int count = userService.addSmbmsRole(smbmsRole); if(count>0){
return "true";
}else{
return"false";
} }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
- 测试过程以及一些注意事项
首先,前端的ajax发送请求时
crossDomain: true,
1
这行代码可以忽略,对结果没有什么较大的影响。
在前台进行设置的时候我还找见一个需要在上面加上以下代码来进行处理,但是对我没有用,你们可以试试
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
1
测试注掉crossDomain: true,对运行不影响,
测试注掉xhrFields: {withCredentials: true},得到的两个Cookie的ID不一致,出现了问题,所以xhrFields: {withCredentials: true},必备
测试后台只写
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
1
运行结果进入方法体,但是返回的时候不会进入success方法,进入error方法并且页面报错信息如下
后台测试只写
response.setHeader("Access-Control-Allow-Credentials", "true");
1
运行结果进入方法体,但是返回的时候不会进入success方法,进入error方法并且页面报错信息如下
后台只写
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
1
会进入后台的方法体,页面都会报错并且弹出error弹窗
测试后台写全
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Credentials", "true");
123
成功进入方法体,结果成功返回,进入success方法并弹出返回的结果,成功的跳转页面
测试只写其中的两个,除了只写这两行代码的时候执行成功,其他两种组合方式都以失败告终
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
12
详细的原因都在代码块的备注中写的很详细了,如果有还不是很懂的可以看下面的链接地址
最终简述一下解决ajax发送跨域的请求的办法
ajax中加入一行代码如下(有的人加上这一句代码后台不用设置就可以,但是我不可以)
xhrFields: {withCredentials: true},
1
Controller的方法体内加入如下两行代码
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
12
问题成功的解决!
顺便说一下,在你需要对session操作的方法体内和ajax请求,如果ajax加了携带Cookie的代码,后台的方法体内没有加上那两行代码的话,可以对数据进行操作,但是return的时候不会正确的进入到success的方法体内,一直会进入到error的方法。但是值尽然操作成功了,而且还是同一个Cookie,这个问题目前未知,后台加上那两行代码的时候,就一切正常了。
问题,为什么我在登录的时候已经携带了Cookie过去,在其他的ajax请求的时候我也都携带了Cookie,那么为什么我在对Cookie的数据进行操作的时候没有任何问题,但是值确不能正确的返回到前台,无法进入success?
刚才测试的时候又出现的一个新的问题,哎,头疼,脑子已经糊了。
我当时解决问题的参考资料:https://blog.csdn.net/cckevincyh/article/details/81140443
进阶资料:https://blog.csdn.net/wzl002/article/details/51441704
进行配置详细解释的进阶资料:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#功能概述
强力推荐研究观看两个进阶资料,看了一遍以后虽说不是能瞬间醒悟但是这个资料里面对一些跨域HTTP(CORS)讲解的非常到位,其实搞了半天才解决的原因还是技术太浅了,综上所述其实前台ajax就一行代码就可以解决,后台的Controller只需要两行代码就可以,就这么三行代码,但是我搞了一个晚上才解决,心累啊,找到了解决办法的那一刻,我突然有种想哭的感觉…希望有人看到了之后可以一起研究学习,也希望能给你们提供到帮助!
好了,问题解决了,欣赏一下小姐姐,放松一下吧