js網(wǎng)絡(luò)請(qǐng)求跨域問(wèn)題匯總(攜帶cookie)

前端程序使用extjs寫(xiě),在本地測(cè)試,發(fā)送請(qǐng)求到服務(wù)器時(shí),發(fā)現(xiàn)存在跨域的問(wèn)題,cookie也沒(méi)有set成功,于是乎在這里整理一下解決過(guò)程

由于篇幅較長(zhǎng),不想看解決過(guò)程的可以翻到最后看總結(jié)
1.跨域允許
2.客戶(hù)端無(wú)法攜帶跨域cookie
3.因?yàn)榧恿藈ithCredentials報(bào)文頭,可是客戶(hù)端不知道服務(wù)器允不允許報(bào)的錯(cuò)
4.由于客戶(hù)端不知道服務(wù)端是否允許POST請(qǐng)求而報(bào)的錯(cuò)

假設(shè)我的服務(wù)器IP是120.111.111.123

# 本地的html
# index.html

<html>
<head>
    <meta charset="utf8">
</head>
<body>
    <input type="button" onclick="request()" value="請(qǐng)求">
</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>
#服務(wù)器的php文件
#path setcookie.php
<?php
session_start();
?>

點(diǎn)擊“請(qǐng)求”按鈕,發(fā)送請(qǐng)求后發(fā)現(xiàn)js報(bào)錯(cuò)

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.

報(bào)這個(gè)錯(cuò)就說(shuō)明我們跨域了,不在允許的訪問(wèn)源,于是乎我在服務(wù)的setcookie.php加入header('Access-Control-Allow-Origin:*');允許所有源

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

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

然后又報(bào)錯(cuò)

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.

這次的報(bào)錯(cuò)是因?yàn)椋诳缬虻臅r(shí)候,extjs不會(huì)直接發(fā)post請(qǐng)求,而是先發(fā)送一個(gè)option請(qǐng)求,看看服務(wù)器允許什么訪問(wèn)頭(比如是不是允許post請(qǐng)求),驗(yàn)證成功后才會(huì)發(fā)送真正的請(qǐng)求

#用谷歌的開(kāi)發(fā)者工具抓的option報(bào)文
OPTIONS /setcookie.php HTTP/1.1
Host: 120.111.111.123
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Access-Control-Request-Headers: x-requested-with
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8

接下來(lái),我們只要發(fā)送我們?cè)试S什么請(qǐng)求頭就行了

#path /setcookie.php

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

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

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

繼續(xù)測(cè)試我們的新功能,成功的解決了跨域問(wèn)題

1.png

but,cookie沒(méi)有“設(shè)置成功”。而之所以沒(méi)有“設(shè)置成功”,是因?yàn)閏ookie存在本地,但是每個(gè)cookie都有一個(gè)domain,當(dāng)你本地的cookie中存在你當(dāng)前訪問(wèn)的域時(shí),才會(huì)被帶過(guò)去,而我的index.html文件是本地訪問(wèn)的,即http://localhost/index.html,而cookie的域是120.111.111.123的,所以不行了。于是乎繼續(xù)改

#path index.html
<html>
<head>
    <meta charset="utf8">
</head>
<body>
    <input type="button" onclick="request()" value="請(qǐng)求">
</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, # 加了這個(gè)
            success: function(transport){
                // do something
            },
            failure: function(transport){
                alert("Error: " - transport.responseText);
            }
        });
    }
    
</script>
</html>

繼續(xù)訪問(wèn),報(bào)錯(cuò)

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.

現(xiàn)在這個(gè)錯(cuò)誤產(chǎn)生的原因就是
1.因?yàn)榧尤肓藈ithCredentials之后,Access-Control-Allow-Origin就不能用“*”了,既然不允許訪問(wèn)這個(gè)源,那我就讓你發(fā)個(gè)報(bào)文頭讓你允許訪問(wèn)唄!

<?php
#path setcookie.php
session_start();
// 是否存在請(qǐng)求源
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');

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

?>

好了,上傳完代碼,繼續(xù)測(cè)試。發(fā)送請(qǐng)求之后,又報(bào)錯(cuò)了(這錯(cuò)中錯(cuò),一個(gè)個(gè)坑搞的大家都看得不耐煩了吧,我保證,這是最后一個(gè)報(bào)錯(cuò)了)

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.

大概的意思就是說(shuō)我給你發(fā)了withCredentials報(bào)文頭,但是你服務(wù)器沒(méi)有跟我說(shuō)允許我?guī)н@個(gè)報(bào)文頭,那么解決方法就是加上允許發(fā)這個(gè)報(bào)文頭的報(bào)文頭

# path setcookie.php
<?php

session_start();
// 是否存在請(qǐng)求源
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');


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

?>

接下來(lái)進(jìn)行最終的測(cè)試,biu~成功了,終于成功了!!!(0.0自己嗨起來(lái)了)

2.png

接下來(lái)總結(jié)一下,之所以跨域會(huì)引起那么多問(wèn)題,都是因?yàn)楣⒅钡目蛻?hù)端,發(fā)什么類(lèi)型的請(qǐng)求都要服務(wù)器允許,而且要明文允許,允許的內(nèi)容包括如下
1.跨域允許
解決方法:服務(wù)器發(fā)送允許客戶(hù)端發(fā)送源的報(bào)文頭
header('Access-Control-Allow-Origin:'.$_SERVER["HTTP_ORIGIN"]);

4.png

2.客戶(hù)端無(wú)法攜帶跨域cookie
這個(gè)時(shí)候就可以在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.因?yàn)榧恿藈ithCredentials報(bào)文頭,可是客戶(hù)端不知道服務(wù)器允不允許報(bào)的錯(cuò)(耿直的客戶(hù)端)
這個(gè)時(shí)候就在服務(wù)器發(fā)送Access-Control-Allow-Credentials

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

4.由于客戶(hù)端不知道服務(wù)端是否允許POST請(qǐng)求而報(bào)的錯(cuò)
這個(gè)時(shí)候要在服務(wù)器端加入

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

以上匯總起來(lái)就是

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');

代碼已經(jīng)放到github了,有啥問(wèn)題歡迎大家指出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,273評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,870評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,742評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,527評(píng)論 6 407
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,010評(píng)論 1 322
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,250評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,769評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,656評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,853評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,103評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,472評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,717評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,487評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,815評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容