[轉] js網絡請求跨域問題彙總(攜帶cookie)

前端程序使用extjs寫,在本地測試,發送請求到服務器時,發現存在跨域的問題,cookie也沒有set成功,因而乎在這裏整理一下解決過程javascript

因爲篇幅較長,不想看解決過程的能夠翻到最後看總結
1.跨域容許
2.客戶端沒法攜帶跨域cookie
3.由於加了withCredentials報文頭,但是客戶端不知道服務器允不容許報的錯
4.因爲客戶端不知道服務端是否容許POST請求而報的錯php

假設個人服務器IP是120.111.111.123html

# 本地的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:*');容許全部源java

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

而後又報錯python

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不會直接發post請求,而是先發送一個option請求,看看服務器容許什麼訪問頭(好比是否是容許post請求),驗證成功後纔會發送真正的請求shell

#用谷歌的開發者工具抓的option報文 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 

接下來,咱們只要發送咱們容許什麼請求頭就好了跨域

#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'); // 容許訪問的有效期 // 功能... // ... 

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

 

 
1.png


but,cookie沒有「設置成功」。而之因此沒有「設置成功」,是由於cookie存在本地,可是每一個cookie都有一個domain,當你本地的cookie中存在你當前訪問的域時,纔會被帶過去,而個人index.html文件是本地訪問的,即http://localhost/index.html,而cookie的域是120.111.111.123的,因此不行了。因而乎繼續改服務器

 

#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以後,Access-Control-Allow-Origin就不能用「*」了,既然不容許訪問這個源,那我就讓你發個報文頭讓你容許訪問唄!

<?php #path setcookie.php session_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
<?php session_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.跨域容許
解決方法:服務器發送容許客戶端發送源的報文頭
header('Access-Control-Allow-Origin:'.$_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報文頭,但是客戶端不知道服務器允不容許報的錯(耿直的客戶端)
這個時候就在服務器發送Access-Control-Allow-Credentials

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');
相關文章
相關標籤/搜索