1、跨域請求: Cross Domain Request:跨功能變數名稱的HTTP請求,瀏覽器從某個功能變數名稱下的資源訪問了另一功能變數名稱下的另一資源(協議、功能變數名稱或是埠號不同); ①瀏覽器允許跨域請求的情形: <img>、<link>、<script>、<iframe> ②禁止跨域請求的情形: XHR——瀏覽器預設出 ...
1、跨域請求:
Cross Domain Request:跨功能變數名稱的HTTP請求,瀏覽器從某個功能變數名稱下的資源訪問了另一功能變數名稱下的另一資源(協議、功能變數名稱或是埠號不同);
①瀏覽器允許跨域請求的情形:
<img>、<link>、<script>、<iframe>
②禁止跨域請求的情形:
XHR——瀏覽器預設出於安全考慮,禁止XHR跨域請求;
③相關名詞及解決方案:
a、相同域:兩個具有相同的協議(如:http)、相同的埠(如:80)、相同的host(主機名),即為相同域,否則構成跨域;
b、file協議:用於訪問本地電腦中的文件;
c、同源策略:跨域之間的腳本是隔離的,一個域中的腳本不能訪問、操作另一個域的絕大部分屬性和方法;同源策略應對一些特殊情況做處理,例:限制file協議下腳本的訪問許可權,本地的HTML文件在瀏覽器中是通過file協議打開的,若腳本能通過file協議訪問到硬碟上的其他任意文件,就會出現安全隱患;
d、單向跨域之JSONP:JSON with Padding;
原理:由於HTML中的script標簽可以載入執行其它域的javascript,所以可以通過script標記動態載入其它域的資源;
實現:在pageB中以javascript的形式聲明pageA所需的數據,然後在pageA中用script標簽將 pageB載入進來,JSONP在此基礎上加入回調函數,pageB載入完後會執行pageA中定義的函數,所需數據以參數形式傳遞給該函數;
限制:JSONP適合在受信任的雙方傳遞數據,否則易被第三方腳本篡改頁面內容,截獲敏感數據;
代碼:
function handleResponse(response){
console.log('The responsed data is: '+response.data);
}
var script = document.createElement('script');
script.src = 'http://www.baidu.com/json/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);
/*handleResonse({"data": "zhe"})*/
//原理如下:
//當我們通過script標簽請求時
//後臺就會根據相應的參數(json,handleResponse)
//來生成相應的json數據(handleResponse({"data": "zhe"}))
//最後這個返回的json數據(代碼)就會被放在當前js文件中被執行
//至此跨域通信完成
e、單向跨域之flash URLLoader:
原理:flash有自己的安全策略,伺服器可以通過crossdomain.xml文件聲明能被哪些域的SWF文件訪問,SWF也可以通過API確定自身能被哪些域的SWF載入,跨域訪問時,可藉助flash發送HTTP請求;
實現:先修改域中crossdomain.xml,將其加入白名單,然後通過Flash URLLoader發送HTTP請求,通過Flash API將響應結果傳遞給javascript;
限制:不支持IOS;
f、單向跨域之Access Control:
原理:瀏覽器發送跨域的HTTP請求,請求包含一個Access-Control-Allow-Origin的HTTP響應頭部,該響應頭聲明瞭請求域的可訪問許可權;
實現:給被跨域訪問的資源添加響應消息頭部,設定允許來自某個功能變數名稱下的頁面訪問當前頁面:header('Access-Control-Allow-Origin:http://xxx.xx');
限制:少數瀏覽器支持(Firefox、Chrome通過XMLHttpRequest,IE8通過XDomainRequest發送請求);
g、單向跨域之window.name:
原理:當window的location變化,重新載入,name屬性依然保持不變;
實現:在pageA中用iframe載入其它域的pageB,在pageB中用javascript把需要傳遞的數據賦值給window.name,iframe載入完成後,pageA修改iframe的地址為同域的一個地址,即可讀出window.name的值;
代碼:
請求代理:
<head>
<script>
function proxy(url, func){
var isFirst = true,
ifr = document.createElement('iframe'),
loadFunc = function(){
if(isFirst){
ifr.contentWindow.location = 'http://a.com/cs1.html';
isFirst = false;
}else{
func(ifr.contentWindow.name);
ifr.contentWindow.close();
document.body.removeChild(ifr);
ifr.src = '';
ifr = null;
}
};
ifr.src = url;
ifr.style.display = 'none';
if(ifr.attachEvent) ifr.attachEvent('onload', loadFunc);
else ifr.onload = loadFunc;
document.body.appendChild(iframe);
}
</script>
</head>
<body>
<script>
proxy('http://www.baidu.com/', function(data){
console.log(data);
});
</script>
</body>
響應:
<script>
window.name = '要傳送的內容';
</script>
h、單向跨域之server proxy:
原理:在數據提供方沒有提供對JSONP或window.name協議的支持,也沒有對其它域開放訪問許可權時,可使用server proxy(伺服器代理)方式抓取數據,跨域的HTTP請求在伺服器端進行,客戶端不用產生跨域的Ajax請求;
實現:在伺服器配置一個代理,將Ajax請求綁定到這個代理路徑下,然後由這個代理髮送Http請求去訪問文件;
限制:該跨域方式不需要和目標資源簽訂協議,帶有侵略性,另需對該代理實施一定程度的保護,如限制他人使用或使用頻率;
i、雙向跨域之document.domain:
原理:同域策略認為域和子域屬於不同的域,修改document的domain屬性為同一host,可以在域和子域或不同子域間通信;
實現:將不同子域document的domain屬性修改為同一host,瀏覽器會認為它們處於同一域下,此時即可互相調用對方的method來通信;
代碼:
請求:
document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
//在這裡操作doc,也就是b.html
ifr.onload = null;
};
響應:
document.domain = 'a.com';
j、雙向跨域之FIM:
原理:Fragment Identiter Messaging,父視窗與iframe可以相互讀寫URL,URL中“#”號及其後面的字元被稱為frag,它一般用於瀏覽器錨點定位,HTTP請求中不會攜帶frag,每個window通過改變其他window的location來發送消息,並通過監聽自己的URL變化來接收消息;
限制:這種方式通信會產生不必要的瀏覽器歷史記錄,且有些瀏覽器不支持onhashchange事件,需要用輪詢來獲知URL的改變,另URL在瀏覽器下有長度限制,制約了每次傳送的數據量;
k、雙向跨域之Flash LocalConnection:
原理:Flash API中有LocalConnection類,該類允許兩個SWF之間進行通信,SWF可以播放在獨立的Flash Player或者AIR中,也可以嵌套在HTML頁面或者PDF中;
實現:在不同域的HTML頁面各自嵌套一個SWF來相互傳遞數據;
限制:數據量有40kb的大小限制,且過程複雜,實用性不強;
l、雙向跨域之window.postMessage:
HTML5定義的新方法,可跨window通信,在較舊瀏覽器中無法使用;
代碼:
請求:
<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
var ifr = document.getElementById('ifr');
var targetOrigin = 'http://b.com'; // 若寫成'http://b.com/c/proxy.html'效果一樣
// 若寫成'http://c.com'就不會執行postMessage了
ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>
響應:
<script type="text/javascript">
window.addEventListener('message', function(event){
// 通過origin屬性判斷消息來源地址
if (event.origin == 'http://a.com') {
alert(event.data); // 彈出"I was there!"
alert(event.source); // 對a.com、index.html中window對象的引用
// 但由於同源策略,這裡event.source不可以訪問window對象
}
}, false);
</script>
m、雙向跨域之Cross Frame:
原理:FIM的變種,藉助空白iframe,不會產生多餘瀏覽器歷史記錄,也不需要輪詢URL的改變;域中pageA和空白代理頁proxyA,另一個域pageB和其空白代理頁proxyB,pageA向pageB發送消息時頁面創建隱藏的iframe,iframe的src指向proxyB,並把message作為URL frag;pageB和proxyB是同域,iframe載入完成後,pageB可以獲得iframe的URL,解析出message,並移除iframe;反向同理;
限制:Opera無法使用,但可使用window.postMessage;
n、動態創建script:
function loadScript(url, func) {
var head = document.head || document.getElementByTagName('head')[0];
var script = document.createElement('script');
script.src = url;
script.onload = script.onreadystatechange = function(){
if(!this.readyState || this.readyState=='loaded' || this.readyState=='complete'){
func();
script.onload = script.onreadystatechange = null;
}
};
head.insertBefore(script, 0);
}
window.baidu = {
sug: function(data){
console.log(data);
}
}
loadScript('http://suggestion.baidu.com/su?wd=w',function(){console.log('loaded')});
//我們請求的內容在哪裡?
//我們可以在chorme調試面板的source中看到script引入的內容
o、Web Socket:
原理:web sockets是一種瀏覽器的API,它的目標是在一個單獨的持久連接上提供全雙工、雙向通信,在JS創建了web socket之後,會有一個HTTP請求發送到瀏覽器以發起連接。取得伺服器響應後,建立的連接會使用HTTP升級從HTTP協議交換為web sockt協議;
代碼:
var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
var data = event.data;
}
限制:只有在支持web socket協議的伺服器上才能正常工作;
2、jQuery中發起JSONP請求的方法:
①$.getJSON兩種方法:
a、使用XHR接收伺服器端返回的JSON響應:
$.getJSON('x.php',function(obj){});
b、使用script標簽執行伺服器返回的script響應——JSONP:
$.getJSON('http://其他功能變數名稱/x.php?callback=?',doResponse);
②$.ajax的兩種方法:
a、使用XHR接收伺服器端返回的響應:
$.ajax({});
b、使用script標簽執行伺服器返回的script響應——JSONP:
$.ajax({
type:'GET',
url:'x.php',
data:{k:v},
dataType:'jsonp',//設定伺服器端返回JSONP數據
success:fn
});
* 本篇內容部分自網上整理而來,請原作者勿怪!