JS網絡請求跨域問題匯總(攜帶餅干)

前端程序使用ExtJS的寫,在本地測試,發送請求到服務器時,發現存在跨域的問題,餅干也沒有一套成功,于是乎在這里整理一下解決過程

由于篇幅較長,不想看解決過程的可以翻譯到最后看

總結1.跨域允許

2.客戶端無法攜帶跨域cookie

3.因為加了與證件報文頭,可能是客戶端不知道服務器允許不允許報的錯

4.由于客戶端不知道服務端是否允許
POST請求而報的錯

假設我的服務器IP是120.111.111.123

本地的html

index.html

<html><head> <meta charset="utf8"></head><body> <input type="button" onclick="request()" value="請求"></body><script type="text/javascript" src="./ext-all.js"></script><script type="text/javascript"> function request(){ Ext.Ajax.request({ url: 'http://120.111.111.123/setcookie.php', method: 'POST', params: { 'text': 'hello world' }, success: function(transport){ // do something }, failure: function(transport){ alert("Error: " - transport.responseText); } }); }</script></html>

服務器的php文件#path setcookie.php

<?php
session_start();
?>

點擊“請求”按鈕,發送請求后發現JS報錯

XMLHttpRequest cannot load http://120.111.111.123/setcookie.php.
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access.

報這個錯就說明我們跨域了,不在允許的訪問源,于是乎我在服務的setcookie.php加入

header('Access-Control-Allow-Origin:*');
網求允許所有源

<?phpsession_start();header('Access-Control-Allow-Origin:*'); // 功能...// ...

然后又報錯

XMLHttpRequest cannot load http://120.111.111.123/setcookie.php. Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers in preflight response.

這次的報錯是因為,在跨域的時候,ExtJS的不會直接發帖子請求,而是先發送一個選項請求,看看服務器允許什么訪問頭(比如是不是允許后請求),驗證成功后才會發送真正的請求

用谷歌的開發者工具抓的option報文OPTIONS /setcookie.php HTTP/1.1Host: 120.111.111.123Connection: keep-alivePragma: no-cacheCache-Control: no-cacheAccess-Control-Request-Method: POSTOrigin: nullUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36Access-Control-Request-Headers: x-requested-withAccept: /Accept-Encoding: gzip, deflate, sdchAccept-Language: zh-CN,zh;q=0.8

接下來,我們只要發送我們允許什么請求頭就行了

path /setcookie.php

session_start();header('Access-Control-Allow-Origin:*');

header('Access-Control-Allow-Methods:OPTIONS, GET, POST'); // 允許option,get,post請求header('Access-Control-Allow-Headers:x-requested-with'); // 允許x-requested-with請求頭header('Access-Control-Max-Age:86400'); // 允許訪問的有效期

// 功能...// ...

繼續測試我們的新功能,成功的解決了跨域問題

1.png

但是,餅干沒有“設置成功”。而之所以沒有“設置成功”,是因為cookie的存在本地,但是每個餅干都有一個域名,當你本地的餅干中存在你當前訪問的域時,才會被帶過去,而我的index.html的文件是本地訪問的,即

[HTTP://localhost/index.html,而餅干的域是120.111.111.123的,所以不行了于是乎繼續改

](http://localhost/index.html%EF%BC%8C%E8%80%8Ccookie%E7%9A%84%E5%9F%9F%E6%98%AF120.111.111.123%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%8D%E8%A1%8C%E4%BA%86%E3%80%82%E4%BA%8E%E6%98%AF%E4%B9%8E%E7%BB%A7%E7%BB%AD%E6%94%B9)

path index.html

<html>
<head>
<meta charset="utf8">
</head>
<body>
<input type="button" onclick="request()" value="請求">
</body>
<script type="text/javascript" src="./ext-all.js"></script>
<script type="text/javascript"> function request(){
Ext.Ajax.request({
url: 'http://120.111.111.123/setcookie.php',
method: 'POST',
params: {
'text': 'hello world'
},
withCredentials: true, # 加了這個
success: function(transport){
// do something
},
failure: function(transport){
alert("Error: " - transport.responseText);
}
});
}

</script>
</html>

繼續訪問,報錯

XMLHttpRequest cannot load http://120.111.111.123/setcookie.php.
Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true.
Origin 'null' is therefore not allowed access.
The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.

現在這個錯誤產生的原因就是

1,因為加入了withCredentials之后,訪問控制允許來源就不能用“*”了,既然不允許訪問這個源,那我就讓你發個報文頭讓你允許
訪問唄!

<?php#path setcookie.phpsession_start();// 是否存在請求源if(isset($_SERVER["HTTP_ORIGIN"])) { header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]); }header('Access-Control-Allow-Methods:OPTIONS, GET, POST');header('Access-Control-Allow-Headers:x-requested-with');header('Access-Control-Max-Age:86400');// 功能...// ...?>

好了,上傳完代碼,繼續測試。發送請求之后,又報錯了(這錯中錯,一個個坑搞的大家都看得不耐煩了吧,我保證,這是最后一個報錯了)

XMLHttpRequest cannot load http://120.111.111.123/setcookie.php.
Response to preflight request doesn't pass access control check: Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'null' is therefore not allowed access.

大概的意思就是說我給你發了withCredentials報文頭,但是你服務器沒有跟我說允許我帶這個報文頭,那么解決方法就是加上允許發這個報文頭的報文頭

path setcookie.php<?phpsession_start();// 是否存在請求源if(isset($_SERVER["HTTP_ORIGIN"])) { header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]); }header('Access-Control-Allow-Origin:null'); header('Access-Control-Allow-Methods:OPTIONS, GET, POST');header('Access-Control-Allow-Headers:x-requested-with');header('Access-Control-Max-Age:86400');header('Access-Control-Allow-Credentials:true');// 功能...// ...?>

接下來進行最終的測試,BIU?成功了,終于成功了!!!(0.0自己嗨起來了)

2.png

接下來總結一下,之所以跨域會引起那么多問題,都是因為耿直的客戶端,發什么類型的請求都要服務器允許,而且要明文允許,允許的內容包括如下

1.網求允許跨域

解決方法:服務器發送允許客戶端發送源的報文頭

標頭( '訪問控制允許來源:'。$ _ SERVER [ “HTTP_ORIGIN”]);

4.png

2.客戶端無法攜帶跨域cookie的

這個時候就可以在ExtJS的中加入withCredentials

Ext.Ajax.request({ url: 'http://120.111.111.123/setcookie.php', method: 'POST', params: { 'text': 'hello world'
},
withCredentials: true, success: function(transport){ // do something
},
failure: function(transport){
alert("Error: " - transport.responseText);
}
});

3.因為加了withCredentials報文頭,可是客戶端不知道服務器允不允許報的錯
(耿直的客戶端)

這個時候就在服務器發送接入控制允許證書

header('Access-Control-Allow-Credentials:true');

4.由于客戶端不知道服務端是否允許
POST而請求作者:的錯

這個時候要在服務器端的加入

header('Access-Control-Allow-Methods:OPTIONS, GET, POST');header('Access-Control-Allow-Headers:x-requested-with');header('Access-Control-Max-Age:86400');

以上匯總起來就是

header('Access-Control-Allow-Methods:OPTIONS, GET, POST');header('Access-Control-Allow-Headers:x-requested-with');header('Access-Control-Max-Age:86400'); header('Access-Control-Allow-Origin:'.$_SERVER['HTTP_ORIGIN']);header('Access-Control-Allow-Credentials:true');header('Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS');header('Access-Control-Allow-Headers:x-requested-with,content-type');header('Access-Control-Allow-Headers:Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With');

代碼已經放到

[github上

](https://github.com/HBLong/extjsCorsDemo)了,有啥問題歡迎大家指出

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容