js跨域问题浅析及解决方法优缺点对比


Posted in Javascript onNovember 08, 2014

什么是跨域?

概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域。

URL                      说明       是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js 同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js 同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js 同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js 同一域名,不同协议 不允许
http://www.a.com/a.js
http://70.32.92.74/b.js 域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js 主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js 不同域名 不允许

对于端口和协议的不同,只能通过后台来解决。

跨域资源共享(CORS)

CROS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CROS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。

<script type="text/javascript">

    var xhr = new XMLHttpRequest();

    xhr.open("GET", "/trigkit4",true);

    xhr.send();

</script>

以上的trigkit4是相对路径,如果我们要使用CORS,相关Ajax代码可能如下所示:

<script type="text/javascript">

    var xhr = new XMLHttpRequest();

    xhr.open("GET", "http://segmentfault.com/u/trigkit4/",true);

    xhr.send();

</script>

代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。

服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。

要解决跨域的问题,我们可以使用以下几种方法:

通过jsonp跨域

现在问题来了?什么是jsonp?维基百科的定义是:JSONP(JSON with Padding)是资料格式 JSON 的一种“使用模式”,可以让网页从别的网域要资料。

JSONP也叫填充式JSON,是应用JSON的一种新方法,只不过是被包含在函数调用中的JSON,例如:

callback({"name","trigkit4"});

JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。 例如:

<script type="text/javascript">

    function dosomething(jsondata){

        //处理获得的json数据

    }

</script>

<script src="http://example.com/data.php?callback=dosomething"></script>

js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。

<?php

$callback = $_GET['callback'];//得到回调函数名

$data = array('a','b','c');//要返回的数据

echo $callback.'('.json_encode($data).')';//输出

?>

最终,输出结果为:dosomething(['a','b','c']);

如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了。

<script type="text/javascript">

    $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){

        //处理获得的json数据

    });

</script>

jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。

JSONP的优缺点

JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

CROS和JSONP对比

CORS与JSONP相比,无疑更为先进、方便和可靠。

    1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。

    2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。

    3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS)。
通过修改document.domain来跨子域

浏览器都有一个同源策略,其限制之一就是第一种方法中我们说的不能通过ajax的方法去请求不同源中的文档。 它的第二个限制是浏览器中不同域的框架之间是不能进行js的交互操作的。
不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:

<script type="text/javascript">

    function test(){

        var iframe = document.getElementById('ifame');

        var win = document.contentWindow;//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的

        var doc = win.document;//这里获取不到iframe里的document对象

        var name = win.name;//这里同样获取不到window对象的name属性

    }

</script>

<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>

这个时候,document.domain就可以派上用场了,我们只要把http://www.example.com/a.html 和 http://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。

1.在页面 http://www.example.com/a.html 中设置document.domain:

<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>

<script type="text/javascript">

    document.domain = 'example.com';//设置成主域

    function test(){

        alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象

    }

</script>

2.在页面 http://example.com/b.html 中也设置document.domain:
<script type="text/javascript">

    document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同

</script>

修改document.domain的方法只适用于不同子域的框架间的交互。

Javascript 相关文章推荐
通用于ie和firefox的函数 GetCurrentStyle (obj, prop)
Dec 27 Javascript
Autocomplete Textbox Example javascript实现自动完成成功
Aug 17 Javascript
学习并汇集javascript匿名函数
Nov 25 Javascript
如何确保JavaScript的执行顺序 之jQuery.html深度分析
Mar 03 Javascript
23个超流行的jQuery相册插件整理分享
Apr 25 Javascript
JS文本框追加多个下拉框的值的简单实例
Jul 12 Javascript
Bootstrap页面布局基础知识全面解析
Jun 13 Javascript
JavaScript实现页面无操作倒计时退出
Oct 22 Javascript
JS实现的添加弹出层并完成锁屏操作示例
Apr 07 Javascript
详解基于 axios 的 Vue 项目 http 请求优化
Sep 04 Javascript
Node.JS循环删除非空文件夹及子目录下的所有文件
Mar 12 Javascript
搭建一个Koa后端项目脚手架的方法步骤
May 30 Javascript
js 操作符汇总
Nov 08 #Javascript
jquery的总体架构分析及实现示例详解
Nov 08 #Javascript
jquery常用方法及使用示例汇总
Nov 08 #Javascript
JQuery遍历json数组的3种方法
Nov 08 #Javascript
JQuery中使用.each()遍历元素学习笔记
Nov 08 #Javascript
jQuery遍历之next()、nextAll()方法使用实例
Nov 08 #Javascript
jQuery遍历对象、数组、集合实例
Nov 08 #Javascript
You might like
apache中为php 设置虚拟目录
2014/12/17 PHP
php根据日期或时间戳获取星座信息和生肖等信息
2015/10/20 PHP
详解PHP swoole process的使用方法
2017/08/26 PHP
基于thinkphp6.0的success、error实现方法
2019/11/05 PHP
PHP 计算至少是其他数字两倍的最大数的实现代码
2020/05/26 PHP
解析Jquery中如何把一段html代码动态写入到DIV中(实例说明)
2013/07/09 Javascript
js如何判断用户是在PC端和还是移动端访问
2014/04/24 Javascript
jQuery点缩略图弹出层显示大图片
2015/02/13 Javascript
js实现a标签超链接提交form表单的方法
2015/06/24 Javascript
js计算系统当前日期是星期几的方法
2016/07/14 Javascript
利用Node.js编写跨平台的spawn语句详解
2017/02/12 Javascript
深入浅析JavaScript中的RegExp对象
2017/09/18 Javascript
vue 关闭浏览器窗口的时候,清空localStorage的数据示例
2019/11/06 Javascript
JavaScript实现模态对话框实例
2020/01/13 Javascript
js 闭包深入理解与实例分析
2020/03/19 Javascript
[05:04]DOTA2上海特级锦标赛主赛事第二日TOP10
2016/03/04 DOTA
Python简单计算给定某一年的某一天是星期几示例
2018/06/27 Python
对python产生随机的二维数组实例详解
2018/12/13 Python
Python Flask框架模板操作实例分析
2019/05/03 Python
python celery分布式任务队列的使用详解
2019/07/08 Python
Python基于Tkinter编写crc校验工具
2020/05/06 Python
python opencv实现简易画图板
2020/08/27 Python
Python gevent协程切换实现详解
2020/09/14 Python
html5实现canvas阴影效果示例
2014/05/07 HTML / CSS
html5实现多图片预览上传及点击可拖拽控件
2018/03/15 HTML / CSS
莫斯科隐形眼镜网上商店:Linzi
2019/07/22 全球购物
高考备战决心书
2014/03/11 职场文书
建议书标准格式
2014/03/12 职场文书
中学生运动会通讯稿大全
2014/09/18 职场文书
解除劳动合同证明书模板
2014/11/20 职场文书
2015年会计年终工作总结
2015/05/26 职场文书
日本读研:怎样写好一篇日本研究计划书?
2019/07/15 职场文书
话题作文之生命的旋律
2019/12/17 职场文书
嵌入式Redis服务器在Spring Boot测试中的使用教程
2021/07/21 Redis
使用Nginx搭载rtmp直播服务器的方法
2021/10/16 Servers
优化Mysql查询的示例
2022/04/26 MySQL