報錯:
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只需要兩行代碼就可以,就這么三行代碼,但是我搞了一個晚上才解決,心累啊,找到了解決辦法的那一刻,我突然有種想哭的感覺…希望有人看到了之后可以一起研究學習,也希望能給你們提供到幫助!
好了,問題解決了,欣賞一下小姐姐,放松一下吧