跨域知識點部分總結

跨域的限制

  • 沒法獲取cookielocalStorageindexDB
  • 沒法得到DOM
  • 沒法發送Ajax

關於cookie

共享cookie

cookie,是服務器端寫入瀏覽器端的小段信息,只有同源的網頁才能共享cookie一級域名相同但二級域名不一樣的網頁只要設置相同的document.domain,就能夠共享cookiehtml

補充知識點:前端

  • 一級域名 qq.com
  • 二級域名 game.qq.comwww.qq.comlol.qq.com
  • 三級域名 lpl.lol.qq.com

上述一段描述來自網上的文章,在此通過測試,提出了部分意見,關於意見是什麼,後面會提到,如今先證實上述描述的不精確性。nginx

驗證的服務器nginx配置:ajax

server {
    listen      8080;
    server_name  w1.gaopeng.com;
    location / {
        root   /Users/gaopeng/Sites/w1.gaopeng.com;
        index  index.html index.htm;
    }
}

server {
    listen      8080;
    server_name  w2.gaopeng.com;
    location / {
        root   /Users/gaopeng/Sites/w2.gaopeng.com;
        index  index.html index.htm;
    }
}
複製代碼

w1.gaopeng.comw2.gaopeng.com文件夾下的index.html內容json

<script>
    document.domain = "gaopeng.com";
</script>
複製代碼

主要目的是設置相同的document.cookie後端

瀏覽器打開w1.gaopeng.com,發現document.domain已經被設置gaopeng.com,此時增長一個cookie 跨域

瀏覽器再打開 w2.gaopeng.com 發現 document.domain已經被設置 gaopeng.com,但依舊沒法獲取上述設置的 cookiegao=peng

此時咱們看下cookie存在的表現: 瀏覽器

咱們發如今 w1.gaopeng.com設置的 cookieDomain=w1.gaopeng.com
發現 w2.gaopeng.com依然沒有上述設置的 cookie


忽然想了一下若是將cookie設置爲二級域名會怎麼樣呢? 在w1.gaopeng.com下,設置cookie bash

此時會發如今 w2.gaopeng.com下,會獲取到剛剛設置的 cookie

再次觀察w1.gaopeng.comw2.gaopeng.comcookie服務器

發現第二次設置的cookie共享了

所以得出告終論,cookie的共享與網站的是否同源並沒有明顯的關係,可否共享應該看cookie自身的domain,若是domain相同,就能夠共享

猜測:存在兩個站點不一樣源(協議、端口不一樣)

A站:https://www.example.com:3443/

B站:http://www.example.com:3445/

因爲cookiedomain都是www.example.com,那麼這兩個頁面的cookie是能夠共享的

關於獲取DOM

iframewindow.open

只有同源的網頁才能獲取DOM,一級域名相同但二級域名不一樣的網頁只要設置相同的document.domain,就獲取DOM

// w1.gaopeng.com/index.html
index01.html
<iframe id="myIFrame" src="http://w2.gaopeng.com:8080/"></iframe>
<script>
  // document.domain = 'gaopeng.com';
  // 若是去掉註釋就能夠獲取到DOM
</script>


// w2.gaopeng.com/index.html
index02.html
<script>
    document.domain = "gaopeng.com";
</script>
複製代碼

經過window.open的實例:

LocalStorage、IndexDB

利用上述方式的document.domain等特性都沒法知足他們的通訊,能夠使用下面的介紹的通訊,方式,在文章最後會介紹localStorage進行徹底不一樣源的網站之間的通訊。

非AJAX而且徹底不一樣源的網站通訊

徹底不一樣源的nginx配置

server {
    listen      8080;
    server_name  w2.gaopeng.com;
    location / {
        root   /Users/gaopeng/Sites/w2.gaopeng.com;
        index  index.html index.htm;
    }
}
server {
    listen      8092;
    server_name  w2.gaopeng1.com;
    location / {
        root   /Users/gaopeng/Sites/w2.gaopeng1.com;
        index  index.html index.htm;
    }
}
複製代碼

在這裏因爲iframewindow.open的機理相似,因此只進行某一個種方式的演示

片斷標識符(iframe)

片斷標識符是指URL後面的#號部分,若是隻是改變片斷標識符,頁面不會從新刷新。

父窗口能夠把信息,寫入子窗口的片斷標識符。

// w2.gaopeng1.com/index.html
index02.html
<button id='button'>改變hash</button>
<iframe id="myIFrame" src="http://w2.gaopeng1.com:8092/"></iframe>
<script>
  var srcUrl  = "http://w2.gaopeng1.com:8092/#" + "gao=peng"
  document.getElementById('button').onclick = function () {
    document.getElementById('myIFrame').src = srcUrl;
  }
</script>

// w2.gaopeng1.com/index.html
demo03.html
<script>
  window.onhashchange = checkMessage;
  function checkMessage() {
    var message = window.location.hash;
    console.log('message', message);
  }
</script>
複製代碼

如圖所示,當點擊改變hash按鈕時,iframe頁面會檢測到hash的變化執行checkMessage方法

window.name(iframe)

瀏覽器窗口有一個window.name,這個屬性的最大特色是,不管是否同源,只要在同一個窗口裏,前一個網頁設置了這個屬性,後一個網頁能夠讀取它。

// w2.gaopeng1.com/index.html
index02.html
<iframe id="myIFrame" src="http://w2.gaopeng1.com:8092/"></iframe>
<script>
  console.log(window.name);
</script>

// w2.gaopeng1.com/index.html
demo03.html
<script>
  window.name = "gao=peng";
</script>
複製代碼

如圖所示,主窗口活動了子窗口設置的window.name

window.postMessage(window.open)

上述的兩種方法都是投機取巧的方式,在HTML5中正式引入了:跨文檔通訊 API

// w2.gaopeng1.com/index.html
index02.html
<iframe id="myIFrame" src="http://w2.gaopeng1.com:8092/"></iframe>
<script>
  // 獲取子窗口的引用
  var win = document.getElementsByTagName('iframe')[0].contentWindow;
  var obj = { name: 'Jack' };
  win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://w2.gaopeng1.com:8092/');
</script>

// w2.gaopeng1.com/index.html
demo03.html
<script>
  window.onmessage = function(e) {
  if (e.origin !== 'http://w2.gaopeng1.com:8092/') return;
  var payload = JSON.parse(e.data);
  switch (payload.method) {
    case 'set':
      localStorage.setItem(payload.key, JSON.stringify(payload.data));
      break;
    case 'get':
      // 獲取父窗口的引用
      var parent = window.parent;
      var data = localStorage.getItem(payload.key);
      parent.postMessage(data, 'http://w2.gaopeng.com:8080/');
      break;
    case 'remove':
      localStorage.removeItem(payload.key);
      break;
  }
};
</script>
複製代碼

AJAX的跨域通訊

解決方案:

  • JSONP
  • WebSocket
  • CORS

主要談論一下CORScookie的影響

如上面兩張圖對比所示,當發起Ajax請求時:

  1. ajax會自動帶上同源的cookie,不會帶上不一樣源的cookie
  2. 能夠經過前端設置withCredentialstrue, 後端設置Header的方式來讓ajax自動帶上不一樣源的cookie,可是這個屬性對同源請求沒有任何影響
  3. 若是ajax請求設置withCredentialstrue,注意: Access-Control-Allow-Origin必須制定特定的URL,不能是*, 且須要加上Access-Control-Allow-Credentials 前端代碼:
// 客戶端也須要設置credentials: "include",否則服務端設置的cookie,也發送不過來
fetch("http://localhost:3000/post_form3", { method: "post", body: formData, credentials: "include" }).then(function(response) {
    return response.json();
}).then(function(data) {
	console.log(data);
}).catch(function(e) {
    console.log(e);
});
複製代碼

後端代碼

app.all('*', function(req, res, next) { 
	// 若是想讓cookie發送至前端,必須設置爲localhost:4000,而不是*
	res.header("Access-Control-Allow-Origin", req.headers.origin);
	res.header("Access-Control-Max-Age", 60); // 預檢請求的有效期
	res.header("Access-Control-Allow-Credentials", true);
	res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
	res.header("Access-Control-Allow-Methods","PUT, POST, GET, DELETE, OPTIONS"); 
	res.header("Content-Type", "application/json;charset=utf-8");
	next(); 
});
複製代碼

關於上述代碼中res.header("Access-Control-Max-Age", 60); // 預檢請求的有效期,預檢請求能夠參考這篇文章

參考文章

瀏覽器同源政策及其規避方法

Ajax不會自動帶上cookie

相關文章
相關標籤/搜索