在开发过程中经常会涉及跨域问题,解决跨域问题的方案也有很多种,接下来就来梳理一下前端跨域的常用方法。
同源策略
何为跨域,跨域是相对于同源而言。协议、域名和端口均相同,则为同源。
浏览器通过同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制,摘抄自MDN。
常见解决方案
document.domain
这种方案主要用于主域相同,子域不同的跨域情况。例如: https://jdc.jd.com/ 和 https://www.jd.com/。
通过在https://www.jd.com/打开一个https://jdc.jd.com/,此时JDC的域名是jdc.jd.com/,通过控制台执行document.domain = ‘jd.com’;。强制设置主域,实现同源。
1 2 3 4 5
| var jdc = window.open('https://jdc.jd.com/'); // JDC 页面加载完成后执行 var divs = jdc.document.getElementsByTagName('div');
$(divs).css('border', '1px solid red');
|
通常的做法是通过iframe加载一个跨域页面资源。因为window.open这个方法在浏览器中会被当做谈广告禁止掉。
http://domain.com/index.html
1 2 3 4
| <iframe id="sub" src="http://sub.domain.com/index.html"></iframe> <script> var username = 'yeseonzhang'; </script>
|
http://sub.domain.com/index.html
1 2 3 4
| <script> document.domain = 'domain.com'; console.log(window.parent.username); </script>
|
window.name
这个方案类似location.hash,需要通过第三个页面进行辅助。
window.name属性是用来获取/设置窗口的名称。需要注意的是,当前窗口的window.name并不会因为页面的重载和跳转而更改,所以可以利用这个特性将跨域的window.name通过重定向到同域页面进行读取。
http://domain-a.com/a.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <script> var iframe = document.createElement('iframe'); /* step 1 加载跨域页面 */ iframe.src = 'http://domain-b.com/b.html'; var domain = 'diff';
/* 监听iframe加载 */ iframe.onload = function () { if ('diff' == domain) { /* step 2 重定向到同域页面 */ iframe.contentWindow.location = 'http://www.domain-a.com/c.html'; domain = 'same'; } else if ('same' == domain) { /* 获取同域资源的window.name信息 */ cb(iframe.contentWindow.name); /* 清空数据 */ iframe.contentWindow.name = ''; } }
function cb (res) { console.log(JSON.parse(res)); } </script>
|
http://domain-b.com/b.html
1 2 3 4 5 6 7
| <scirpt> /* 写入相关数据 */ var obj = { username: 'yeaseonzhang' } window.name = JSON.stringify(obj); </script>
|
http://domain-a.com/c.html
同域c页面,可以是一个空页面,不需要进行任何操作。
JSONP
JSONP(JSON with Padding)是JSON的一种使用方式。这种方式允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据。