概念css
1995年有Netscape公司引入的一个安全策略,如今全部浏览器都在使用这个策略。它限制了一个源从另一个源请求资源,用于隔离潜在恶意文件。html
什么才是不一样的源前端
咱们都知道通常的地址又下面三部分组成node
只要两个地址其中有一个不相同,那么这两个地址就是不一样的源。jquery
举个例子nginx
//地址
http://www.address.com/item/page.html
协议: http://
域名:www.example.com
端口:8080(http)/443(https) (端口默认省略)
http://www.address.com/item2/other.html:同源
http://address.com/item/other.html:不一样源(域名不一样)
http://v2.www.address.com/item/other.html:不一样源(域名不一样)
http://www.address.com:81/item/other.html:不一样源(端口不一样)
复制代码
同源的目的ajax
目的是为了保护用户信息的安全,防止恶意网站窃取数据,不然Cookie能够共享。有的网站通常会把一些重要信息存放在cookie或者LocalStorage中,这时若是别的网站可以获取获取到这个数据,可想而知,这样就没有什么安全可言了。npm
限制范围json
目前共有三种行为受到限制后端
原理
script、img、iframe等标签的src属性都拥有跨域请求资源的能力,咱们能够把js、css、img等资源放到一个独立域名的服务器上。而后经过动态建立script标签,再请求一个回调函数的网址,服务器把须要传递的参数塞入这个回调函数中, 而后咱们在js代码中执行这个函数就可已获取到你想要的参数。
前端原生实现
<script> window.xxx = function (value) { console.log(value) } var script = document.createElement('script') script.src = 'https://www.address.com:433/json?callback=xxx' document.body.appendChild(script) </script> 复制代码
jquery实现
$.ajax({ type: "get", url: "https://www.address.com:433/json", dataType: "jsonp", jsonp: "callback", jsonpCallback:"xxx"//自定义回调函数名 success: function(res){ console.log(res) }, error: function(){ console.log('fail'); } }); 复制代码
jsonp插件
//安装 npm install jsonp const jsonp = require('jsonp'); jsonp('https://www.address.com:433/json', {parma:'xxx'}, (err, data) => { if (err) { console.error(err.message); } else { console.log(data); } }); 复制代码
node.js egg 服务端
//须要看egg官网构建一个simple框架 egg-init --type=simple // router.js 用egg内置jspnp方法 https://eggjs.org/api/Config.html#jsonp module.exports = app => { app.get('/json', app.jsonp({ callback: 'xxx' }), app.controller.json.index) } 复制代码
缺点
原理
CORS(Cross-Origin Resource Sharing)跨资源分享,浏览器不能低于IE10,服务器支持任何类型的请求。
熟悉几个后台须要设置的字段
字段必传,为*表示容许任意域名的请求。当有cookie须要传递时,须要指定域名。
字段可选,默认为false,表示是否容许发送cookie。若容许,通知浏览器也要开启cookie值的传递。
字段可选。若是想要浏览器拿到getResponesHeader()其余字段,就在这里指定。
必须字段,非简单请求时设置的字段,例如PUT请求。
指定额外的发送头信息,以逗号分割字符串。
前端原生代码
var xhr = new XMLHttpRequest() // 设置携带cookie xhr.withCredentials = true; xhr.open('POST', 'https://www.address.com:433/json', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.send(null) xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { console.log(JSON.parse(xhr.responseText).msg) } } 复制代码
后端代码
module.exports = app => { class CrosController extends app.Controller { * index(req) { this.ctx.set('Access-Control-Allow-Origin', 'https://www.address.com'); this.ctx.set('Access-Control-Allow-Credentials', 'true') this.ctx.body = { msg: 'hello world' } } } return CrosController } 复制代码
优势
缺点
原理
也是利用iframe能够在不一样域中传值的特色,而location.hash正好能够携带参数,因此利用iframe做为这个不一样域之间的桥梁。
具体实现步骤
A域名页面
var iframe = document.createElement('iframe') iframe.src = 'http://www.B.com:80/hash.html' document.body.appendChild(iframe) window.onhashchange = function () { //处理hash console.log(location.hash) } 复制代码
B域名页面
var xhr = new XMLHttpRequest() xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { var res = JSON.parse(xhr.responseText) console.log(res.msg) parent.location.href = `http://www.A.com:80/a.html#msg=${res.msg}` } } xhr.open('GET', 'http://www.B.com:80/json', true) xhr.send(null) 复制代码
缺点
原理
原理实际上是和上面的方法同样,区别在于window.name可以传递2MB以上的数据。
A域名页面
var iframe = document.createElement('iframe') iframe.src = 'http://www.B.com:80/name.html' document.body.appendChild(iframe) var times = 0 iframe.onload = function () { if (times === 1) { console.log(JSON.parse(iframe.contentWindow.name)) destoryFrame() } else if (times === 0) { times = 1 } } // 获取数据之后销毁这个iframe,释放内存; function destoryFrame() { document.body.removeChild(iframe); } 复制代码
B域名页面
var xhr = new XMLHttpRequest() xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { window.name = xhr.responseText location.href = 'http://www.A.com:80/a.html' } } xhr.open('GET', 'http://www.B.com:80/json', true) xhr.send(null) 复制代码
原理
postMessage是H5原生API支持,能够在两个页面或者多个页面,以及不一样源页面之间传递数据。窗口之间可以传递数据的前提是必须从一个窗口获取到另一个窗口的目标对象(target window),好比说用iframe打开另一个窗口,咱们得获取到这个iframe的contentWindow。或者经过window.open()打开另一个窗口时会返回这个窗口的window对象。
参数传递
/** data 须要传递的数据,使用JSON.stringify 序列化 origin 设置为'*'时,表示传递给全部窗口,也能够指定地址。 若是是同源下设置为'/' **/ postMessage(data,origin) 复制代码
// 打开一个新的窗口 var popup = window.open('http://localhost:8080'); /// 等待新窗口加载完 setTimeout(function() { // 当前窗口向目标源传数据 popup.postMessage({"age":10}, 'http://localhost:8080'); }, 1000); 复制代码
// 设置监听,若是有数据传过来,则打印 window.addEventListener('message', function(e) { console.log(e); //判断是否是目标地址 if(e.origin !== 'http://localhost:8069')return; // console.log(e.source === window.opener); // true //发回数据 e.source.postMessage({"age":20}, e.origin); }); 复制代码
以上五种是比较常见的跨域解决方案,各有优缺点。没有绝对的最优方案,只有最合适应用场景。
常见的两种代理跨域
配置就不讲了,其实我也不熟悉,平时工做用不到这么高大上的。就来说讲原理以及思路。
什么是代理
既然是代理跨域,那么代理(Proxy Server)就是一个很重要的点,这里的代理说的服务器代理,是一种很重要的服务器安全功能,也是一种很常见的设计模式,来隔毫不同的模块,解耦模块。生活中也很容易见到这种模式,咱们买房(买不起呀)买车,就比如跟一个大型服务器打交道,别人是大老板,天然不会那么容易亲自接待你,这时候有中介在中间,帮大家两方理清好思路,作好铺垫,而后后面的交流才会更加顺通高效。咱们浏览器访问不一样源的服务器是有限定的,可是nginx和node中间件这些代理就没有跨域的限定,因此咱们能够放心的把任务交给他们,让他们帮咱们去作咱们作不了的事。
为何代理是反的
咱们知道单个服务器的处理能力是有限的,就比如如中国也不可能只有一家汽车生产商,中国那么大的市场,天然须要不少生产商才能知足的过来。那么用户选购的时候须要节省时间和精力,汽车之间就承担这样一个角色,把成千上万的用户需求分配出去,nginx就可以把用户的请求分发到空闲的服务器上,而后服务器返回本身的服务到负载均衡设备上,而后负载均衡的设备会讲服务器的服务返回给用户,因此咱们并不知道为何服务的是哪一台服务器发送出来的,这就很好的隐藏了服务器。有一句精辟的话是这么说的:“反向代理就是流量发散状,代理是流量汇聚状。”
最后附上一张画的很丑陋的图
若是大神您想继续探讨或者学习更多知识,欢迎加入QQ或者微信一块儿探讨:854280588
![]()
![]()