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>