跨域问题及其解决方法(JSONP&CORS)
一、什么是跨域
当a.qq.com域名下的页⾯或脚本试图去请求b.qq.com域名下的资源时,就是典型的跨域行为。跨域的定义从受限范围可以分为两种,⼴义跨域和狭义跨域。

(一)广义跨域
⼴义跨域通常包含以下三种⾏为:
1. 资源跳转:a链接、重定向。
2. 资源嵌⼊:<link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等⽂件外链。
3. 脚本请求:浏览器存储数据读取、dom和js对象的跨域操作、js发起的ajax请求等。
其中,资源跳转和资源嵌⼊⾏为可以正常请求到跨域资源,脚本请求在未经任何处理的情况下,通常会有跨域
(二)狭义跨域
狭义跨域正是浏览器同源策略限制的⼀类请求场景,即我们通常说的跨域⾏为,通常包含以下三种⾏为:
1. cookie、localStorage和indexDB⽆法读取。
2. dom和js对象⽆法获取和操作。
3. ajax请求⽆法发送
二、常见的跨域场景
浏览器安全的基石就是“同源策略”,即如果A网站设置的cookie,B网站如果想访问必须满足三个要求:同一种协议、同一个域名、同一个端口号。
举例来说,http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口号是80(可以省略,http默认80,https默认443)
例如:
http://www.example.com/dir2/other.html :同源
http://example.com/dir/other.html :不同源(域名不同)
http://v2.www.example.com/dir/other.html :不同源(域名不同
http://www.example.com:81/dir/other.html :不同源(端口不同)
三、跨域解决方法
(一)ajax跨域请求解决方案
1.jsonp跨域解决
jsonp (JSON with Padding),是JSON的⼀种“使⽤模式”,可以让⽹页跨域读取数据。其本质是利⽤script标签的开放策略,浏览器传递callback参数到后端,后端返回数据时会将callback参数作为函数名来包裹数据,从⽽浏览器就可以跨域请求数据并定制函数来⾃动处理返回数据。

var script = document.createElement('script');
script.type = 'text/javascript';
// 传参callback给后端,后端返回时执⾏这个在前端定义的回调函数
script.src = 'http://a.qq.com/index.php?callback=handleCallback';
document.head.appendChild(script);
// 回调执⾏函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
- jsonp跨域优点:
jsonp兼容性强,适⽤于所有浏览器,尤其是IE10及以下浏览器。
- jsonp跨域缺点:
没有关于调⽤错误的处理。
只⽀持GET请求,不⽀持POST请求以及⼤数据量的请求,⽽且也⽆法拿到相关的返回头,状态码等数据。
callback参数恶意注⼊,可能会造成xss漏洞。
2.跨域资源共享(CORS)
跨域资源共享(Cross-origin resource sharing,CORS)是⼀个 W3C标准,允许浏览器向跨域服务器发送请求,从⽽克服了ajax只能同源使⽤的限制。CORS需要浏览器和服务器同时⽀持。⽬前,所有主流浏览器(IE10及以上)使⽤XMLHttpRequest对象都可⽀持该功能,IE8和IE9需要使⽤XDomainRequest对象进⾏兼容。
CORS整个通信过程都是浏览器⾃动完成,浏览器⼀旦发现ajax请求跨源,就会⾃动在头信息中增加Origin字段,⽤来说明本次请求来⾃哪个源(协议+域名+端⼝)。因此,实现CORS通信的关键是服务器,需要服务器配置Access-Control-Allow-Origin头信息。当CORS请求需要携带cookie时,需要服务端配置Access-Control-Allow-Credentials头信息,前端也需要设置withCredentials。浏览器将CORS请求分成两类:简单请求和⾮简单请求。简单请求需要满⾜以下两⼤条件:
1. 请求⽅法是以下三种⽅法之⼀:HEAD、GET、POST。
2. HTTP的头信息不超出以下⼏种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type:只限
于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain。
CORS简单请求跨域实现流程:

// IE8/9需⽤XDomainRequest兼容
var xhr = new XMLHttpRequest();
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://a.qq.com/index.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=saramliu');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
- CORS跨域优点:
⽀持所有类型的HTTP请求,功能完善。
通过onerror事件监听进⾏调⽤错误处理;
通过Access-Control-Allow-Origin进⾏资源访问授权。
- CORS跨域缺点:
⽬前主流浏览器(IE10及以上)都⽀持CORS,但IE8和IE9需要使⽤XDomainRequest对象进⾏兼容,IE7及以下浏览器不⽀持
3.服务器代理
服务器代理,顾名思义即在发送跨域请求时,后端进⾏代理中转请求⾄服务器端,然后将获取的数据返回给前端。⼀般适⽤于以下场景:
针对IE7及以下浏览器摒弃Flash插件的情况,配置代理接⼝与前端页⾯同源,并中转⽬标服务器接⼝,则ajax请求不存在跨域问题。外⽹前端页⾯⽆法访问内⽹接⼝,配置代理接⼝允许前端页⾯访问,并中转内⽹接⼝,则外⽹前端页⾯可以跨域访问内⽹接⼝。
服务器代理实现流程:

- 服务器代理优点:
在不使⽤Flash的情况下,兼容不⽀持CORS的浏览器跨域请求。
- 服务器代理缺点:
后端需要⼀定的改造⼯作量。
(⼆)前端跨域通信解决⽅案
前端跨域通信是指浏览器中两个不符合同源策略的前端页⾯进⾏通信。
1.document.domain+iframe

document.domain+iframe⽅案代码⽰例:
<!-- A页⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq.com/b.html"></iframe>
<script>
document.domain = "qq.com";
var windowB = document.getElementById("iframe").contentWindow;
alert("B页⾯的user变量:" + windowB.user);
</script>
<!-- B页⾯ http://b.qq.com/b.html -->
<script>
document.domain = "qq.com";
var user = "saramliu";
</script>
- document.domain+iframe⽅案优点:
实现逻辑简单,⽆需额外中转页⾯
- document.domain+iframe⽅案缺点:
仅适⽤于主域相同,⼦域不同的前端通信跨域场景
2.location.hash+iframe
当两个不符合同源策略且主域不同的页⾯需要进⾏跨域通信时,可以利⽤url的hash值改变但不刷新页⾯的特性,实现简单的前端跨域通信。

<!-- A页⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
// 监听c.html传来的hash值
window.onhashchange = function () {
alert("B页⾯传递数据:" + location.hash.substring(1));
};
</script>
<!-- B页⾯ http://b.qq1.com/b.html -->
<iframe id="iframe" src="http://a.qq.com/c.html"></iframe>
<script>
// 向c.html传递hash值
var iframe = document.getElementById('iframe');
setTimeout(function() {
iframe.src = iframe.src + '#user=saramliu';
}, 1000);
</script>
<!-- C页⾯ http://a.qq.com/c.html -->
<script>
// 监听b.html传来的hash值
window.onhashchange = function () {
// 操作同域a.html的hash值,传递数据
window.parent.parent.location.hash = window.location.hash.substring(1);
};
</script>
- location.hash+iframe⽅案优点
可以解决主域不同的前端通信跨域问题。
hash改变,页⾯不会刷新。
- location.hash+iframe⽅案缺点:
受部分浏览器安全机制限制,需要额外的同源中转页⾯,且中转页⾯需要js逻辑来修改hash值。
通信数据类型及长度均受限,且数据外显在url上,存在⼀定安全风险。
3.window.name+iframe
window.name属性的独特之处在于,name值在不同页⾯(甚⾄不同域名)加载后依旧存在,并且可以⽀持⾮常长的name值(2MB)。
window.name+iframe代码⽰例:
<!-- A页⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
var state = 0;
var iframe = document.getElementById('iframe');
iframe.onload = function() {
if (state === 1) {
// 第2次onload成功后,读取同域window.name中数据
alert(iframe.contentWindow.name);
} else if (state === 0) {
// 第1次onload成功后
state = 1;
}
};
</script>
<!-- B页⾯ http://b.qq1.com/b.html -->
<script>
window.name = "这⾥是B页⾯!";
window.location = "http://a.qq.com/c.html";
</script>
- window.name+iframe⽅案优点:
可以解决主域不同的前端通信跨域问题。
通信数据类型不受限,且长度可达2MB。
- window.name+iframe⽅案缺点:
需要额外的同源中转页⾯,但中转页可以为空⽩页。
4.postMessage
postMessage是HTML5 XMLHttpRequest Level2中的API,且是为数不多可以跨域操作的window属性之⼀,它通常⽤于解决以下⽅⾯的问题:
1. 页⾯和其打开的新窗⼝的数据传递。
2. 多窗⼝之间消息传递。
3. 页⾯与嵌套iframe消息传递。
postMessage是⼀种安全的跨域通信⽅法。当a.html获得对b.html的window对象后,a.html调⽤postMessage⽅法分发⼀个MessageEvent消息。b.html通过监听message事件即可获取a.html传递的数据,从⽽实现跨域通信。
- postMessage⽅法的语法如下:
otherWindow.postMessage(message、targetOrigin、[transfer])
otherWindow:⽬标窗⼝的window对象,⽐如iframe的contentWindow属性、执⾏window.open返回的window对象等。
message:将要发送给其他window的数据。
targetOrigin:指定哪些窗⼝能接收到消息事件,其值可以是字符串*(表⽰⽆限制)或者是“协议+主机+端⼝号”。
transfer(可选):是⼀串和message同时传递的Transferable对象,这些对象的所有权将被转移给消息的接收⽅,⽽发送⼀⽅将不再保有所有权。
postMessage⽅案代码⽰例:
<!-- A页⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = {meesage: "这⾥是A页⾯发的消息"};
var url = "http://b.qq1.com/b.html";
// 向B页⾯发送消息
iframe.contentWindow.postMessage(JSON.stringify(data), url);
};
window.addEventListener("message", function(e) {
alert("B页⾯发来消息:" + JSON.parse(e.data));
});
</script>
<!-- B页⾯ http://b.qq1.com/b.html -->
<script>
window.addEventListener("message", function(e) {
alert("A页⾯发来消息:" + JSON.parse(e.data));
var data = {meesage: "这⾥是B页⾯发的消息"};
var url = "http://a.qq.com/a.html";
window.parent.postMessage(JSON.stringify(data), url);
}, false);
</script>
- postMessage⽅案优点:
可以解决多种类型的前端跨域通信问题;
- postMessage⽅案缺点:
兼容性⽅⾯相对差⼀点,IE8及以下浏览器不⽀持该⽅法,IE9只⽀持postMessage传递string类型的数据,⽽标准的postMessage消
息数据可以是任何类型。
跨域问题及其解决方法(JSONP&CORS)的更多相关文章
- jquery ajax跨域的完美解决方法(jsonp方式)
ajax跨域请求的问题,JQuery对于Ajax的跨域请求有两类解决方案,不过都是只支持get方式,接下来为大家详细介绍下客户端JQuery.ajax的调用代码 今天在项目中需要做远程数据加载 ...
- 跨域请求解决方法(JSONP, CORS)
1.跨域 假设我们页面或者应用部署在 http://www.aaa.com 上了,而我们打算从 http://www.bbb.com 请求提取数据.一般情况下,如果我们直接使用 AJAX 来请求将会失 ...
- jQuery ajax跨域请求的解决方法
在Ajax应用中,jQuery的Ajax请求是非常容易而且方便的,但是初学者经常会犯一个错误,那就是Ajax请求的url不是本地或者同一个服务器下面的URI,最后导致虽然请求200,但是不会返回任何数 ...
- Thinkphp5.1允许uni-app的H5跨域请求接口解决方法
情景: uni-app使用vue框架开发混合APP,虽然APP或者小程序没有跨域,但希望就是写完这个既有H5,又有APP,小程序等,所以能通过后端解决跨域最好.但是不知道是vue的原因还是什么,在PH ...
- .Net 站点跨域问题及解决方法
一.什么是站点跨域 了解跨域之前, 先了解下什么同源策略?百度百科:同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功 ...
- json跨域原理及解决方法
这一篇文章呢,主要是之前一直听别人讲json跨域跨域,但是还是一头雾水,只知其一,于是一怒之下,翻阅各种资料,如果有不正确的地方,劳烦指正一下^_^ 首先,先了解浏览器有一个很重要安全性限制,即为同源 ...
- AJAX及其跨域的主要解决方法
AJAX = Asynchronous JavaScript andXML(异步的 JavaScript 和 XML).通过在后台与服务器进行少量数据交换,使网页实现异步更新.要明白异步交互可以通过同 ...
- Jquery DataTable AJAX跨域请求的解决方法及SSM框架下服务器端返回JSON格式数据的解决方法
如题,用HBuilder开发APP,涉及到用AJAX跨域请求后台数据,刚接触,费了不少时间.幸得高手指点,得以解决. APP需要用TABLE来显示数据,因此采用了JQ 的DataTable. 在实现 ...
- react+spring 记录跨域问题的解决方法
react 跨域访问后台,默认是有跨域问题,并且火弧和谷歌浏览器,对跨域问题展示还不一样. 谷歌浏览器如下图: 此处状态是200,然而在Response却没有任何信息,如下图 然而火弧浏览器,对该问题 ...
随机推荐
- 安装ESLint
安装ESLint ESLint是静态代码检查工具,配合TypeScript使用可以帮助检查TypeScript的语法和代码风格. 添加ESLint到当前工程,yarn add -D eslint. 使 ...
- javascript入门教程(二):变量
大家好,我从今天开始就会正式讲javascript的语法方面.变量 js中的变量一般使用var来声明(es6的let不在本教程讨论范围内),可以用来定义任何种类的变量,如果只对变量进行了定义而没有赋值 ...
- DIV 上下左右居中黑科技
<style> #info{height:0px; width:0px;top:50%; left:50%;position:absolute;} #center{background:# ...
- 一步步搭建物联网系统——无处不在的CSS
无处不在的CSS 或许你觉得CSS一点儿也不重要,而事实上,如果说HTML是建筑的框架,CSS就是房子的装修.那么Javascript呢,我听到的最有趣的说法是小三--还是先让我们回到代码上来吧. C ...
- jsp笔记---标签
<meta>标签 <meta> 标签提供了 HTML 文档的元数据.元数据不会显示在客户端,但是会被浏览器解析. META元素通常用于指定网页的描述,关键词,文件的最后修改时间 ...
- 小程序安卓端播放不了音频解决方法wx.createInnerAudioContext()
在小程序播放音频时,使用组件wx.createInnerAudioContext(),安卓端无法播放音频. 我的情况:播放服务器上传来的音频,格式为mp3.首先查看你的格式是否符合文档要求 在安卓端进 ...
- 实战-DRF快速写接口(认证权限频率)
实战-DRF快速写接口 开发环境 Python3.6 Pycharm专业版2021.2.3 Sqlite3 Django 2.2 djangorestframework3.13 测试工具 Postma ...
- c语言实现循环单链表
//初始化 Node*InitList() { Node*head=(Node*)malloc(sizeof(Node)); head->next=NULL; head->data=-1; ...
- 三、DOS命令
常用的DOS命令 #盘符切换 D: #查看当前目录下的所有文件 dir #切换目录 cd+空格+/d+空格+路径 #返回上一级 cd+空格+.. #清理屏幕 cls #退出终端 exit #查看电脑 ...
- 实现深拷贝还在用JSON.parse(JSON.stringify(obj))?带你用JS实现一个完整版深拷贝函数
使用JavaScript实现深拷贝 1.JSON序列化实现深拷贝 在JS中,想要对某一个对象(引用类型)进行一次简单的深拷贝,可以使用JSON提供给我们的两个方法. JSON.stringfy():可 ...