js跨域


 第一次寫博客,好緊張,不知道能寫成啥樣,哈哈哈。

自己的一知片解,有錯請多多指教,嘻嘻嘻。

一、何為跨域?

只要協議、域名、端口后任何一個不同,就是跨域。

舉個例子:

http://www.example.com 協議不同
https://www.example.com
http://www.example.com 域名不同
http://www.test.com
http://www.example.com 端口不同
http://www.example.com:81

 

 

 

 

 

 

注意:ip相同,域名不同,也是跨域。(在本地寫demo時,配置host文件,127.0.0.1配置了兩個域名,糾結是否算跨域,試了一下,是的)

二、跨域的類型

1.cookie

只有同源的網頁才能共享cookie

2.iframe

網格網頁不同源,無法拿到對方的DOM

3.ajax

只能請求同源的網址,否則報錯

三、解決跨域

我在我電腦的host文件里配置了兩個域名模擬跨域。

以下,test1代表www.test1.myhost.com; test2代表www.test2.myhost.com

1.cookie

存在這樣一種情況能夠實現共享cookie:兩個網頁一級域名形同,二級域名不同,設置cookie時,指定兩個網頁的domain相同,便可以共享cookie啦。

test1:

document.cookie = 'key1= value1; domain=myhost.com';
console.log(document.cookie);//"key1 = value1"

test2:

console.log(document.cookie);//"key1 = value1"

就醬紫,他倆共享cookie了,好可怕

打開application看看,發現這cookie原來在myhost.com域名下。

2.iframe

一個頁面中嵌套一個iframe,這個iframe的src與主頁面跨域。這樣的話,主頁面獲取操作iframe的DOM,iframe也無法操作主頁面的DOM

test1為主頁面,test2為嵌入的iframe

解決iframe跨域的,寶寶只知道這三種:

(1)片段識別符

(2)window.name

(3)window.postMessage

2.1 片段識別符

指的是URL中#后面的部分,只改變片段識別符,頁面不會重新刷新。

實現思路:

父窗口可以把要傳遞的數據寫入iframe的src片段識別符中,iframe通過監聽hashchange事件得到通知,獲取數據

同樣道理,子窗口也可以改變父窗口的片段識別符,達到同樣的效果。示例來嘍:

父→子:

主頁面

var origin  = $('iframe').attr('src');
$('iframe').attr('src', origin + '#主窗口');

iframe

console.log(window.location.hash);//"#主窗口"

子→父:

iframe

parent.location.href ='http://www.test1.myhost.com:8080/tutor/cookie#iframe'

主頁面

console.log(window.location.hash);//"#iframe"

2.2 window.name

瀏覽器窗口有window.name屬性,它的特點是無論是否同源,只要在同一個窗口中,前一個網頁設置了這個屬性,后一個網頁就可以讀取它

實現思路:

將iframe需要與主頁面傳遞的數據寫到iframe的window.name中,完成后將iframe的src設置成與主頁面同源,此時,主頁面與iframe就同源了,就可以拿到對方的數據啦,而iframe的src更改並不影響window.name的值啊,主頁面便可以輕松讀取iframe中window.name的值啦,是不是很機智!再來個例子吧。

iframe

window.name = '哈哈哈,我是iframe';
location.href = 'http://www.test1.myhost.com:8080/這里就是一個與主頁面同源的頁面';

主頁面

console.log($('iframe')[0].contentWindow.name);//"哈哈哈,我是iframe"

2.3 window.postMessage

html5引入的新API,允許跨窗口通信,不論這兩個窗口是否同源。

window.postMessage(data, url); //data為要傳給目標的數據,url為目標的url。

注意,此window是目標窗口的window,不是本窗口的window

同樣來個例子:

子→父:

iframe

top.postMessage('hello', 'http://www.test1.myhost.com:8080/tutor/cookie');

主頁面

window.addEventListener('message', function(e) {
  console.log(e.data);//"hello"
}, false);

父→子:

主頁面

$('.post').on('click', function() {
   $('iframe')[0].contentWindow.postMessage('hello hello', 'http://www.test2.myhost.com:8080/這里就是一個目標url');
});

iframe

window.addEventListener('message', function(e) {
  console.log(e.data);//"hello hello"
}, false);

這里的e有幾個重要屬性:

a.data:傳遞來的message

b.source:發送消息的窗口對象

c.origin:發送消息窗口的源(協議+主機+端口號)

3.ajax

誒嘿,寶寶知道的也是三種,哈哈哈,好巧啊

(1)JSONP

(2)websocket

(3)CORS

分別說說吧

3.1 JSONP

原理就是利用script腳本擁有跨域能力。

基本思想是,網頁添加一個script元素,src放需要請求的接口,這種做法不受同源策略的限制。服務器收到請求后,將數據放在一個指定的回調函數里傳回來。

這種方法簡單適用,老式的瀏覽器全部支持,服務器改造也非常小。

js實現:

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

$('.ajax').on('click', function() {
  addScriptTag('http://www.php.myhost.com/jsonp.php?callback=foo');
});

function foo(data) {
  console.log('response data is: ' + data);
};

jQuery實現:

$('.ajax').on('click', function() {
  $.ajax({
    url: 'http://www.php.myhost.com/jsonp.php',
    type: 'get',
    dataType: 'jsonp',
    jsonpCallback: 'foo',
    data: {}
  });
});

function foo(data) {
  console.log('Your response is: ' + data);
};

PHP代碼:

<?php

$callback = $_GET['callback'];
$data = 'hello';
echo $callback.'('.json_encode($data).')';

?>

3.2 websocket

websocket是一種通信協議。該協議不實行同源策略,只要服務器支持,就可以通過它進行跨源通信。

例如,長連接呀

其實不太懂,就先不說它了哈

3.3 CORS

開始扯啦

CORS是跨源資源分享(Cross-Origin Resource Sharing)的縮寫。它是W3C標准,是跨源AJAX請求的根本解決方法。

CORS請求分為兩類:簡單請求和非簡單請求,太多了,這里就先不介紹了,一查就知道了。

簡單請求就是瀏覽器發出CORS請求時,http頭當中增加一個域(origin)的信息。該域包含協議名、地址及一個可選的端口,用來說明本次請求來自哪個源,服務器根據這個值決定是否同意這次請求。(這都是瀏覽器代為發送,開發者的代碼無法觸及到)

如果這個指定的源不在許可范圍內,服務器就返回一個正常的http回應。但是回應中沒有Access-Control-Allow-Origin字段,拋出異常,XMLHttpRequest的onerror捕獲。

如果這個指定的源在許可范圍內,會多出幾個頭信息字段(都以Access-Contrl-開頭)

非簡單請求(我平常請求的接口都是非簡單請求,因為content-type為application/json)是在發起正式通信之前增加一次http查詢,實現詢問服務器當前網頁所在域名是否在許可名單中,得到肯定答復后瀏覽器才會發出正式的XMLHttpRequest請求,否則報錯。

預檢請求的方式是options,頭信息里面關鍵字段是origin,表示來自哪個源。服務器收到預檢請求后檢查origin,確認是否允許跨源請求,就可以做出回應了。

允許請求:在http回應中,關鍵是Access-Control-Allow-Origin字段,如:Access-Control-Allow-Origin:http://api.com,表示http://api.com可以請求數據。設為*,表示同意任何跨域。

不允許請求:會返回一個正常的http回應,但沒有任何CORS相關的頭信息字段,瀏覽器會認為不同意預檢請求,觸發一個錯誤,被XMLHttpRequest的onerror捕獲。

總而言之,普通跨域請求,只要服務端設置Access-Control-Allow-Origin即可,前端無須設置。帶cookie請求,需要前后端都設置字段。注意,所帶cookie為跨域請求接口所在域的cookie,而非當前頁的。

查了一下前端帶cookie請求咋實現:

js

 var xhr = new XMLHttpRequest(); // 前端設置是否帶cookie 
 xhr.withCredentials = true;

jquery

  $.ajax({
    xhrFields: {        
      withCredentials: true // 前端設置是否帶cookie    
    },
  });

vue:

vue框架在vue-resource封裝的ajax組件中加入以下代碼:
Vue.http.options.credentials = true

ok ,總算寫完啦~~~

哦,對了,加一下ajax跨域的幾種現象(這幾種現象這個博客說的很好:http://www.cnblogs.com/dailc/p/5893341.html#crossDomain_crosPrinciple)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM