對跨域問題的理解

Why : 爲何會產生跨域問題javascript

由瀏覽器的同源策略(協議+域名+端口)致使。同源策略是基於瀏覽器安全角度產生的。html

How : 如何解決跨域問題前端

1.經過jsonp方式,原理是使用<script>的src自己支持跨域vue

優勢:低版本瀏覽器也可使用 

缺點:只支持get方法,且只能夠用於傳遞數據沒法進行DOM查詢,安全性低,必須後端配合。

一:原生實現html5

<!DOCTYPE html>  
<html lang="en">  
<head>  
	<meta charset="UTF-8">  
	<title>JSONP實現跨域</title>  
</head>  
<body>  
	<div id="mydiv">  
		<button id="btn">點擊</button>  
	</div>  
</body>
<script>
	function handleResponse(res){  
	    console.log(JSON.stringify(res));  
	} 
</script>
<script type="text/javascript">  
	window.onload = function() {  
	var oBtn = document.getElementById('btn');  
	oBtn.onclick = function() { 0  
		var script = document.createElement("script");  
		// 傳參並指定回調執行函數爲callBack
		script.src = "http://xxxx.com?callback=handleResponse";  
		document.body.insertBefore(script, document.body.firstChild);
	};  
};  
</script>  
</html>

二:jq ajax實現java

<!DOCTYPE html>  
<html lang="en">  
	<head>  
		<meta charset="UTF-8">  
		<title>jQuery實現JSONP</title>  
	</head>

	<body>  
		<div id="mydiv">  
			<button id="btn">點擊</button>  
		</div>  
	</body>  
	<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.0.min.js"></script>  
	<script type="text/javascript">  
		$(function() {  
			$("#btn").click(function() {  
				$.ajax({  
					async: true,  
					url: "http://xxxx.com",  
					type: "GET",  
					dataType: "jsonp", // 請求方式爲jsonp  
					jsonp: 'callback', //指定一個查詢參數名稱來覆蓋默認的 jsonp 回調參數名 callback  
					jsonpCallback: 'handleResponse',//自定義回調函數名
					data: {  
						count: 1  
					},  
					success: function(response, status, xhr) {  
						console.log('狀態爲:' + status + ',狀態是:' + xhr.statusText);  
						console.log(response);  
					}  
				});  
			});  
		});  
	</script>  
</html>>

三:vue.js: vue實現jquery

this.$http.jsonp('http://xxx.com', {
  params: {},
  jsonp: 'callBack'
}).then((res) => {
  console.log(res); 
})

2.使用CORS(跨域資源共享)設置請求頭ios

普通跨域請求:只服務端設置Access-Control-Allow-Origin便可,前端無須設置,若要帶cookie請求:先後端都須要設置。ajax

需注意的是:因爲同源策略的限制,所讀取的cookie爲跨域請求接口所在域的cookie,而非當前頁。json

一、 前端設置

1)原生ajax

// 前端設置是否帶cookie
xhr.withCredentials = true;

示例代碼:
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端設置是否帶cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('canshu=xxx');

xhr.onreadystatechange = function() {
  if (xhr.readyState == 4 && xhr.status == 200) {
	alert(xhr.responseText);
  }
};

2)jQuery ajax

$.ajax({
...
  xhrFields: {
	withCredentials: true // 前端設置是否帶cookie
  },
  crossDomain: true, // 會讓請求頭中包含跨域的額外信息,但不會含cookie
...
});

3)vue框架

1/axios設置:
axios.defaults.withCredentials = true

2/vue-resource設置:
Vue.http.options.credentials = true

3.使用 iframe 配合 window 自帶的 name 屬性

優勢:操做簡單,不要求後端配合

缺點:name的大小有限制,通常是2M左右

window.name屬性的獨特之處:name值在不一樣的頁面(甚至不一樣域名)加載後依舊存在,而且能夠支持很是長的 name 值(2MB)。

(1)a.html:(http://www.domain1.com/a.html)
var proxy = function(url, callback) {
  var state = 0;
  var iframe = document.createElement('iframe');
  // 加載跨域頁面
  iframe.src = url;
  // onload事件會觸發2次,第1次加載跨域頁,並留存數據於window.name
  iframe.onload = function() {
	if (state === 1) {
	  // 第2次onload(同域proxy頁)成功後,讀取同域window.name中數據
	  callback(iframe.contentWindow.name);
	  destoryFrame();
	} else if (state === 0) {
	  // 第1次onload(跨域頁)成功後,切換到同域代理頁面
	  iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';
	  state = 1;
	}
  };
  document.body.appendChild(iframe);
  // 獲取數據之後銷燬這個iframe,釋放內存;這也保證了安全(不被其餘域frame js訪問)
  function destoryFrame() {
	iframe.contentWindow.document.write('');
	iframe.contentWindow.close();
	document.body.removeChild(iframe);
  }
};
// 請求跨域b頁面數據
proxy('http://www.domain2.com/b.html', function(data){
  alert(data);
});

(2)proxy.html:(http://www.domain1.com/proxy....
  中間代理頁,與a.html同域,內容爲空便可。
  
(3)b.html:(http://www.domain2.com/b.html)
<script>
  window.name = 'This is domain2 data!';
</script>

4.使用h5新增的postMessage方法

優勢:操做簡單,不要求後端配合

缺點:早期瀏覽器不支持

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是爲數很少能夠跨域操做的window屬性之一,它可用於解決如下方面的問題:

a.) 頁面和其打開的新窗口的數據傳遞

b.) 多窗口之間消息傳遞

c.) 頁面與嵌套的iframe消息傳遞

d.) 上面三個場景的跨域數據傳遞

用法:postMessage(data,origin)方法接受兩個參數

data: html5規範支持任意基本類型或可複製的對象,但部分瀏覽器只支持字符串,因此傳參時最好用JSON.stringify()序列化。

origin: 協議+主機+端口號,也能夠設置爲"*",表示能夠傳遞給任意窗口,若是要指定和當前窗口同源的話設置爲"/"。

(1)a.html:(http://www.domain1.com/a.html)
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script> 
  var iframe = document.getElementById('iframe');
  iframe.onload = function() {
	var data = {
	  name: 'xxx'
	};
  // 向domain2傳送跨域數據
  iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
  };
  // 接受domain2返回數據
  window.addEventListener('message', function(e) {
	alert('data from domain2 ---> ' + e.data);
  }, false);
</script>


(2)b.html:(http://www.domain2.com/b.html)
<script>
  // 接收domain1的數據
  window.addEventListener('message', function(e) {
	alert('data from domain1 ---> ' + e.data);
	var data = JSON.parse(e.data);
	if (data) {
	  data.number = 16;
	  // 處理後再發回domain1
	  window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
	}
  }, false);
</script>
相關文章
相關標籤/搜索