什么是跨域请求?javascript
当浏览器执行一个脚本时会检查是否同源,只有同源的脚本才会执行,若是不一样源即为跨域html
什么是同源?前端
同源即:由Netscape提出的著名安全策略,是浏览器最核心、基本的安全功能,它限制了一个源(origin)中加载文本或者脚本与来自其余源(origin)中资源的交互方式
,所谓的同源就是指协议、域名、端口相同。java
只要协议、域名、端口有任何一个不一样,都被看成是不一样的域,之间的请求就是跨域操做。
协议?域名?端口?web
协议:网络协议遍布OSI通讯模型(OSI七层模型,经常使用协议有TCP/IP、HTTP、FTP协议等)
域名:Domain Name,网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)
端口:是设备与外界通信交流的出口,分为物理端口和虚拟端口(常见的如80端口)json
了解概念后咱们知道跨域请求就是web浏览器自身不容许在域名、协议、端口等都不相同的状况下进行页面请求方为,所以做为前端developer在项目开发时是须要解决此类问题的!后端
为何要有这种限制?非同源请求页面会怎么样?跨域
设想这样一个情景:A网站是一家银行,用户登陆之后,又去浏览其余的网站B,若是网站B能够读取A网站的Cookie,会发生什么问题?
显然,若是Cookie包含隐私(好比存款总额),这些信息就会泄露,更可怕的是,Cookie每每用来保存用户的登陆状态,若是用户没有退出登陆,其余网站就能够冒用户,随心所欲。由于浏览器同时还规定,提交表单不受同源策略的限制。浏览器
非同源限制范围安全
跨域请求解决方案
1. jsonp:(JSON with Padding是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题)
原理:网页客户端动态添加<script>标签添加src属性,向服务端发送json请求(不受同源策略束缚)服务器收到请求后,将数据放在一个指定名字的回调函数里(做为参数)传回来。
// 前端请求代码 //http://127.0.0.1:8888/jsonp.html var script = document.createElement('script'); script.src = 'http://127.0.0.1:2333/jsonpHandler?callback=_callback' document.body.appendChild(script); //插入script标签 //回调处理函数 _callback var _callback = function(obj){ for(key in obj){ console.log('key: ' + key +' value: ' + obj[key]); } } // 后端响应代码 //http://127.0.0.1:2333/jsonpHandler app.get('/jsonpHandler', (req,res) => { let callback = req.query.callback; let obj = { type : 'jsonp', name : 'weapon-x' }; res.writeHead(200, {"Content-Type": "text/javascript"}); res.end(callback + '(' + JSON.stringify(obj) + ')'); })
JSONP只支持Get请求方式
2.CORS:(跨域资源共享)是由W3C制定的跨站资源分享标准,可让AJAX实现跨域访问,除了 GET 要求方法之外也支持其余的 HTTP 要求。服务器通常须要增长以下响应头的一种或几种:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
跨域请求默认不会携带Cookie信息,若是须要携带,请配置下述参数:
"Access-Control-Allow-Credentials": true // Ajax设置 "withCredentials": true
3.window.name+iframe:利用iframe标签的跨域能力,window.name属性值在文档刷新后依旧存在的能力(且最大容许2M左右)
<!-- 下述用端口 10000表示:domainA 10001表示:domainB --> <!-- localhost:10000 --> <script> var iframe = document.createElement('iframe'); iframe.style.display = 'none'; // 隐藏 var state = 0; // 防止页面无限刷新 iframe.onload = function() { if(state === 1) { console.log(JSON.parse(iframe.contentWindow.name)); // 清除建立的iframe iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); } else if(state === 0) { state = 1; // 加载完成,指向当前域,防止错误(proxy.html为空白页面) // Blocked a frame with origin "http://localhost:10000" from accessing a cross-origin frame. iframe.contentWindow.location = 'http://localhost:10000/proxy.html'; } }; iframe.src = 'http://localhost:10001'; document.body.appendChild(iframe); </script> <!-- localhost:10001 --> <!DOCTYPE html> ... <script> window.name = JSON.stringify({a: 1, b: 2}); </script> </html>
4.window.name:window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的全部页面中的,并不会因新页面的载入而进行重置。
<script> //a页面设置 window.name="kowalski"; </script> <script> //b页面取出 alert(window.name); </script>
正在接触后续补充...