報(bào)錯(cuò):
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,因?yàn)閯偨佑|沒多久springboot,所以遇到了一堆的問題,首先這個(gè)springboot我這里建立的是沒有web.xml配置文件的,所以在設(shè)置過濾器的時(shí)候,不知道在哪里設(shè)置,導(dǎo)致網(wǎng)上查的一堆在web.xml通過filter設(shè)置的過濾器解決跨域問題,我這里都沒有用,還有寫一寫配置文件或者是寫一個(gè)類文件,配置文件沒有,類文件沒有用。于是我找了一個(gè)晚上,終于找到了解決的辦法以及原因,詳細(xì)如下。 - 前臺(tái)的代碼塊如下
<!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>
<!--一個(gè)簡單的form表單,測試通過button點(diǎn)擊事件,ajax來進(jìn)行post方式的攜帶參數(shù)發(fā)送請求,所以這里沒必要寫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")
/*點(diǎn)擊按鈕的時(shí)候給一個(gè)點(diǎn)擊事件*/
$button.click(function(){
/*得到輸入框內(nèi)的值*/
var userCode = $("#userCode").val();
var userPassword = $("#userPassword").val();
$.ajax({
type:"post",
/*你要往哪里發(fā)送請求*/
url:"http://localhost:8080/doLogin",
data:{
"userCode":userCode,
"userPassword":userPassword
},
/*設(shè)置xhrFields: {withCredentials: true},為true時(shí)。
發(fā)送Ajax時(shí),Request header中便會(huì)帶上 Cookie 信息,否則不攜帶Cookie
測試結(jié)果如果不寫或者不為true的話,后臺(tái)的session.getid()不是同一個(gè)*/
xhrFields: {withCredentials: true},
/*crossDomain: true。發(fā)送Ajax時(shí),Request header 中會(huì)包含跨域的額外信息,
但不會(huì)含cookie。*/
crossDomain: true,
dataType:"text",
success:function(result){
/*如果成功的話彈一下后臺(tái)返回的值并且跳轉(zhuǎn)頁面到登錄成功的頁面*/
alert(result)
window.location.href="index.html";
},
error:function(){
alert("出錯(cuò)了")
}
});
})
</script>
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
- 后臺(tái)代碼塊如下,注:這個(gè)是springboot項(xiàng)目
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 聲明這個(gè)是個(gè)controller并且返回的數(shù)據(jù)類型可以為json
* @CrossOrigin springboot中支持跨域的注解
* */
@RestController
@CrossOrigin
public class UserController {
/**
* @Resource 自動(dòng)注入的注解
* */
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private UserService userService;
/**
* 進(jìn)行登錄驗(yàn)證的方法
* 接受ajax傳遞過來的參數(shù)
* 這里還需要session,response,request來進(jìn)行一些跨域的設(shè)置
* 親測,最終成功運(yùn)行并且結(jié)果返回為true
* */
@RequestMApping("/doLogin")
public String doLogin(@RequestParam("userCode")String userCode,
@RequestParam("userPassword")String userPassword,
HttpSession session, HttpServletResponse response, HttpServletRequest request){ /**
* 測試的輸出一下發(fā)送請求的域名
* 最主要的解決問題的代碼來了,我這里為了盡量闡述明白查閱了好多資料,寫了大量的注釋,希望大家可以看的更明白一點(diǎn)
* */
System.out.println(request.getHeader("Origin"));
/**
*在響應(yīng) header 中設(shè)置 ‘*’ 來允許來自所有域的跨域請求訪問
* 較靈活的設(shè)置方式 允許這個(gè)域名進(jìn)行訪問,request.getHeader("Origin"),通過request.getHeader('Origin')來得到訪問來源的域名
* 這行代碼很重要,必須寫
* */
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
/**
* 首部字段 Access-Control-Allow-Headers 表明服務(wù)器允許請求中攜帶字段 X-PINGOTHER 與 Content-Type。
* Access-Control-Allow-Headers 的值為逗號分割的列表
* 這個(gè)可以不寫,寫這個(gè)就是表明服務(wù)器允許請求中攜帶的字段
* */
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
/**
* 前臺(tái)ajax發(fā)送的請求中對應(yīng)客戶端的 xhrFields.withCredentials: true 參數(shù)
* 服務(wù)器端通過在響應(yīng) header 中設(shè)置 Access-Control-Allow-Credentials = true 來運(yùn)行客戶端攜帶證書式訪問。
* 通過對 Credentials 參數(shù)的設(shè)置,就可以保持跨域 Ajax 時(shí)的 Cookie。這里需要注意的是:
* 服務(wù)器端 Access-Control-Allow-Credentials = true時(shí),參數(shù)Access-Control-Allow-Origin 的值不能為 '*'
* 這是因?yàn)檎埱蟮氖撞恐袛y帶了 Cookie 信息
* 如果服務(wù)器端的響應(yīng)中未攜帶 Access-Control-Allow-Credentials: true ,瀏覽器將不會(huì)把響應(yīng)內(nèi)容返回給請求的發(fā)送者。
* 這行代碼也必須加
* */
response.setHeader("Access-Control-Allow-Credentials", "true");
System.out.println(session.getId());
System.out.println("進(jìn)入了登錄驗(yàn)證的方法");
SmbmsUser smbmsUser = userService.getUser(userCode,userPassword); session.setAttribute("smbmsUser",smbmsUser);
if(smbmsUser!=null){
return "true";
}else{
return "false";
} } /**
* 增加數(shù)據(jù)的控制層方法
* 這里也需要使用到session,response來進(jìn)行一系列的設(shè)置
* */
@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("進(jìn)入增加數(shù)據(jù)的方法");
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
- 測試過程以及一些注意事項(xiàng)
首先,前端的ajax發(fā)送請求時(shí)
crossDomain: true,
1
這行代碼可以忽略,對結(jié)果沒有什么較大的影響。
在前臺(tái)進(jìn)行設(shè)置的時(shí)候我還找見一個(gè)需要在上面加上以下代碼來進(jìn)行處理,但是對我沒有用,你們可以試試
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
1
測試注掉crossDomain: true,對運(yùn)行不影響,
測試注掉xhrFields: {withCredentials: true},得到的兩個(gè)Cookie的ID不一致,出現(xiàn)了問題,所以xhrFields: {withCredentials: true},必備
測試后臺(tái)只寫
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
1
運(yùn)行結(jié)果進(jìn)入方法體,但是返回的時(shí)候不會(huì)進(jìn)入success方法,進(jìn)入error方法并且頁面報(bào)錯(cuò)信息如下
后臺(tái)測試只寫
response.setHeader("Access-Control-Allow-Credentials", "true");
1
運(yùn)行結(jié)果進(jìn)入方法體,但是返回的時(shí)候不會(huì)進(jìn)入success方法,進(jìn)入error方法并且頁面報(bào)錯(cuò)信息如下
后臺(tái)只寫
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
1
會(huì)進(jìn)入后臺(tái)的方法體,頁面都會(huì)報(bào)錯(cuò)并且彈出error彈窗
測試后臺(tái)寫全
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
成功進(jìn)入方法體,結(jié)果成功返回,進(jìn)入success方法并彈出返回的結(jié)果,成功的跳轉(zhuǎn)頁面
測試只寫其中的兩個(gè),除了只寫這兩行代碼的時(shí)候執(zhí)行成功,其他兩種組合方式都以失敗告終
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
12
詳細(xì)的原因都在代碼塊的備注中寫的很詳細(xì)了,如果有還不是很懂的可以看下面的鏈接地址
最終簡述一下解決ajax發(fā)送跨域的請求的辦法
ajax中加入一行代碼如下(有的人加上這一句代碼后臺(tái)不用設(shè)置就可以,但是我不可以)
xhrFields: {withCredentials: true},
1
Controller的方法體內(nèi)加入如下兩行代碼
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
12
問題成功的解決!
順便說一下,在你需要對session操作的方法體內(nèi)和ajax請求,如果ajax加了攜帶Cookie的代碼,后臺(tái)的方法體內(nèi)沒有加上那兩行代碼的話,可以對數(shù)據(jù)進(jìn)行操作,但是return的時(shí)候不會(huì)正確的進(jìn)入到success的方法體內(nèi),一直會(huì)進(jìn)入到error的方法。但是值盡然操作成功了,而且還是同一個(gè)Cookie,這個(gè)問題目前未知,后臺(tái)加上那兩行代碼的時(shí)候,就一切正常了。
問題,為什么我在登錄的時(shí)候已經(jīng)攜帶了Cookie過去,在其他的ajax請求的時(shí)候我也都攜帶了Cookie,那么為什么我在對Cookie的數(shù)據(jù)進(jìn)行操作的時(shí)候沒有任何問題,但是值確不能正確的返回到前臺(tái),無法進(jìn)入success?
剛才測試的時(shí)候又出現(xiàn)的一個(gè)新的問題,哎,頭疼,腦子已經(jīng)糊了。
我當(dāng)時(shí)解決問題的參考資料:https://blog.csdn.net/cckevincyh/article/details/81140443
進(jìn)階資料:https://blog.csdn.net/wzl002/article/details/51441704
進(jìn)行配置詳細(xì)解釋的進(jìn)階資料:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#功能概述
強(qiáng)力推薦研究觀看兩個(gè)進(jìn)階資料,看了一遍以后雖說不是能瞬間醒悟但是這個(gè)資料里面對一些跨域HTTP(CORS)講解的非常到位,其實(shí)搞了半天才解決的原因還是技術(shù)太淺了,綜上所述其實(shí)前臺(tái)ajax就一行代碼就可以解決,后臺(tái)的Controller只需要兩行代碼就可以,就這么三行代碼,但是我搞了一個(gè)晚上才解決,心累啊,找到了解決辦法的那一刻,我突然有種想哭的感覺…希望有人看到了之后可以一起研究學(xué)習(xí),也希望能給你們提供到幫助!
好了,問題解決了,欣賞一下小姐姐,放松一下吧






