对跨域问题的理解

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>
相关文章
相关标签/搜索