一个iOS程序员眼中的跨域问题
2017-02-17 00:00
169 查看
摘要: 跨域问题是web开发领域一个常见的问题,相信每个web开发者都遇到“跨域”的问题
最近公司的iOS开发任务比较少,所以自己最近开始了Web开发的任务,在用H5做了很多页面,所做的东西和之前客户端界面一模一样,只是做好h5搬到微信上。本人开发环境:html开发ide一会用HBulder一会儿用Sublime。
为
了模拟真实的环境,所以HBulder新建了WebApp,跑起来可以针我的大玫瑰金上运行看效果(iphone6s plus玫瑰金)。我很傻的以为手机上运行没错就没问题了,不会存在传说中的<b>跨域问题</b>,没想到周五下午要合并代码到Dev分支,才发现合并进去页面报错。
只能怪自己"too young too naive",回头一想,原来App请求接口类似于C/S不存在跨域问题。而网页这种方式只要协议、域名、端口、有一个不一致就会导致跨域,由于自己所做的页面有40多,所以改起来烦的要死,问同事除了将数据放进url后来形成类似http://xxx/com?s=xx&q=yy这种形式有木有其他办法?最后找出一种快速修改的方法,见下面代码
修改前
修改后
最后查了相关的资料发现跨域问题大体有3种解决方案:(1)、代理;(2)、JSONP(支持get请求);(3)、XHR2;(4)、CORS跨域资源共享;(5)、通过修改document.domain来解决iframe跨域问题;(6)、window.name进行跨域;(7)、HTML5的window.postMessage方法
具体说明:基于浏览器的安全考虑,由于同源策略的限制,不同域名、不同端口、不同协议的对象不能互相调用。(其实浏览器成功发送请求并拿回了数据 只是浏览器的同源策略 禁止了获取 )
代理:通过统一域名下的Web服务器创建一个代理。
举例说明:www.hangzhou.com的a.html需要调用www.shanghai.com下的b.php服务,显然这违反了同源策略,所以就需要通过代码这个方法去解决问题。具体怎么做?可以在www.hangzhou.com下可以写个exchange.php。将去请求www.shanghai.com下的服务,之后将结果返回给a.html。这样访问www.hangzhou.com/exchange.php的效果等于访问www.shanghai.com的服务
JSONP:JSON with padding。是JSON的一种使用方式,适用于主流浏览器的跨域访问问题。JSONP由2部分组成:回调函数和数据
js文件载入成功后会执行我们在url参数中指定的函数,所以JSONP是需要服务端进行配合的。
XHR2:HTML5提供的XMLHttpRequest Level2已经实现了跨域访问以及其他的一些新功能。但不适配所有浏览,比如IE10以下的版本均不支持。
此外还需要在服务端修改
header('Access-Controller-Allow-Origin:*');
header('Access-Controller-Allow-Methods:POST、GET');
CORS跨域资源共享:Cross-Origin Resource Sharing定义了进行访问跨域资源时浏览器如何与服务器通信。
如果使用CORS
代码与之前的代码差别就是使用了绝对路径。服务端对于CORS的支持在于Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
CORS和JSONP对比
1、JSONP只可以实现get请求,CORS可以所有类型的HTTP请求
2、CORS开发者可以使用普通的XMLHTTPRequest请求和获取数据
3、JSONP支持较老的浏览器,而老版本的浏览器不支持CORS
通过修改document.domain来跨域
浏览器的同源策略限制之一就是不能通过Ajax去请求不同源的文档,限制之二就是浏览器中不同域的框架之间是不能进行js交互。
不同框架之间可以获取window对象,但是window对象的属性和方法不可获取到。
http://www.hangzhou.com/a.html的一个frame的src是http://www.xihu.hangzhou.com/b.html这时候document.domain就可以上场了,
不过需要注意,document.domain的设定有限制,必须设置成自身或比自身更高一级的父域,且主域必须相同。
在页面http://xihu.hangzhou.com/b.html也需要设置
通过window.name来跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的
HTML5的window.postMessage方法跨域
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
传送门:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy、http://www.ruanyifeng.com/blog/2016/04/cors.html
最近公司的iOS开发任务比较少,所以自己最近开始了Web开发的任务,在用H5做了很多页面,所做的东西和之前客户端界面一模一样,只是做好h5搬到微信上。本人开发环境:html开发ide一会用HBulder一会儿用Sublime。
为
了模拟真实的环境,所以HBulder新建了WebApp,跑起来可以针我的大玫瑰金上运行看效果(iphone6s plus玫瑰金)。我很傻的以为手机上运行没错就没问题了,不会存在传说中的<b>跨域问题</b>,没想到周五下午要合并代码到Dev分支,才发现合并进去页面报错。
只能怪自己"too young too naive",回头一想,原来App请求接口类似于C/S不存在跨域问题。而网页这种方式只要协议、域名、端口、有一个不一致就会导致跨域,由于自己所做的页面有40多,所以改起来烦的要死,问同事除了将数据放进url后来形成类似http://xxx/com?s=xx&q=yy这种形式有木有其他办法?最后找出一种快速修改的方法,见下面代码
修改前
$.ajax({ type: "post", url: early_children_url , data:urlJson, success: function(data) { console.log(storageData); swal({ //省略...
修改后
var neonataldetail = '{' + '"babyinfoid":"' + earlyBabyInfoId + '",' + '"days":"' + day + '",' + '"feedingtimes":"' + feedingtimes + '",' + '"feedingway":"' + feedingway + '",' + '"stoolfrequency":"' + stoolfrequency + '",' + '"urinate":"' + urinate + '",' + '"yellowish":"' + yellowish + '",' + '"weight":"' + weight + '"' + '}'; var dataJson = { "type": early_children_perinatal_type, "neonataldetail": JSON.parse(neonataldetail) }; var urlJson = JSON.stringify(dataJson); $.ajax({ dataType: "jsonp", type: "post", url: early_children_url + "?s=" + urlJson, success: function(data) { console.log(storageData); swal({ title: "提交成功", text: "", showCancelButton: false, closeOnConfirm: false, showLoaderOnConfirm: true }, function(data) { window.location.href = "early-children.html"; }); }, error: function() { swal("上传失败,请检查网络后重试"); } });
最后查了相关的资料发现跨域问题大体有3种解决方案:(1)、代理;(2)、JSONP(支持get请求);(3)、XHR2;(4)、CORS跨域资源共享;(5)、通过修改document.domain来解决iframe跨域问题;(6)、window.name进行跨域;(7)、HTML5的window.postMessage方法
具体说明:基于浏览器的安全考虑,由于同源策略的限制,不同域名、不同端口、不同协议的对象不能互相调用。(其实浏览器成功发送请求并拿回了数据 只是浏览器的同源策略 禁止了获取 )
代理:通过统一域名下的Web服务器创建一个代理。
举例说明:www.hangzhou.com的a.html需要调用www.shanghai.com下的b.php服务,显然这违反了同源策略,所以就需要通过代码这个方法去解决问题。具体怎么做?可以在www.hangzhou.com下可以写个exchange.php。将去请求www.shanghai.com下的服务,之后将结果返回给a.html。这样访问www.hangzhou.com/exchange.php的效果等于访问www.shanghai.com的服务
JSONP:JSON with padding。是JSON的一种使用方式,适用于主流浏览器的跨域访问问题。JSONP由2部分组成:回调函数和数据
//www.hangzhou.com <script type="text/javascript"> function getArg(data){ //处理数据 } </script> <script type="text/javascript" src="http://www.shanghai.com/showUser.php?callback=getArg."></script>
js文件载入成功后会执行我们在url参数中指定的函数,所以JSONP是需要服务端进行配合的。
//www.shanghai.com <?php $callback = $_GET['callback'];//得到回调函数名 $data = array('a','b','c');//要返回的数据 echo $callback.'('.json_encode($data).')';//输出 ?>
XHR2:HTML5提供的XMLHttpRequest Level2已经实现了跨域访问以及其他的一些新功能。但不适配所有浏览,比如IE10以下的版本均不支持。
此外还需要在服务端修改
header('Access-Controller-Allow-Origin:*');
header('Access-Controller-Allow-Methods:POST、GET');
window.onload = function () { var xhr = new XMLHttpRequest(); //判断浏览器是否支持XHR2 if (xhr.withCredentials === undefined) return false; xhr.open("get", "http://www.baidu.com"); xhr.onreadystatechange = function () { if (xhr.readyState !== 4) return;//忽略未完成的调用 if (xhr.status === 200) { console.log(xhr.responseText); } } xhr.send(null); }
CORS跨域资源共享:Cross-Origin Resource Sharing定义了进行访问跨域资源时浏览器如何与服务器通信。
<script type=""> var xhr = new XMLHTTPRequest(); xhr.open("get","/showUser.php"); xhr.send(); </script>
如果使用CORS
<script type=""> var xhr = new XMLHTTPRequest(); xhr.open("get","http://hangzhou.com/showUser.php"); xhr.send(); </script>
代码与之前的代码差别就是使用了绝对路径。服务端对于CORS的支持在于Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
CORS和JSONP对比
1、JSONP只可以实现get请求,CORS可以所有类型的HTTP请求
2、CORS开发者可以使用普通的XMLHTTPRequest请求和获取数据
3、JSONP支持较老的浏览器,而老版本的浏览器不支持CORS
通过修改document.domain来跨域
浏览器的同源策略限制之一就是不能通过Ajax去请求不同源的文档,限制之二就是浏览器中不同域的框架之间是不能进行js交互。
不同框架之间可以获取window对象,但是window对象的属性和方法不可获取到。
http://www.hangzhou.com/a.html的一个frame的src是http://www.xihu.hangzhou.com/b.html这时候document.domain就可以上场了,
不过需要注意,document.domain的设定有限制,必须设置成自身或比自身更高一级的父域,且主域必须相同。
<iframe id = "iframe" src="http://xihu.hangzhou.com/b.html" onload="showUser()"></iframe> <script type="text/javascript"> document.domain = 'hangzhou.com';//设置成主域 function showUser(){ alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象 } </script>
在页面http://xihu.hangzhou.com/b.html也需要设置
<script type="text/javascript"> document.domain = 'hangzhou.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同 </script>
通过window.name来跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的
HTML5的window.postMessage方法跨域
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
传送门:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy、http://www.ruanyifeng.com/blog/2016/04/cors.html
相关文章推荐
- 一个让98%的Java程序员犯难的偏门问题!
- 一个让98%的Java程序员犯难的偏门问题!
- 一个程序员眼中的团队原型思考
- CSDN博客:对于一个程序员,写程序就是实现功能,遇到具体问题,解决这个问题,并记录问题到CSDN上,从而有所提高和互相帮助。
- 一个非C++程序员问的C++问题
- 一个程序员大家都关心的问题.
- 一个程序员眼中的团队原型思考(1)-个体的孤独和团队的力量
- 你要面试一个程序员,应该问他什么问题
- 一个程序员眼中的团队原型思考(3)---- 个体的孤独和团队的力量
- iOS开发的一个问题集锦
- 一个让98%的Java程序员犯难的偏门问题!
- 一个程序员眼中的中国软件业
- 一个程序员眼中的中国软件业
- 某项目要调用现有的100多个DLL 三 先解决为一个类型做一个跨域的问题
- 一个程序员眼中的团队原型思考(1)-个体的孤独和团队的力量
- 一个让98%的Java程序员犯难的偏门问题!
- 关于COOKIES跨域总结(通过一个问题)
- 学习Java的第一步是安装好JDK,写一个Hello World, 其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰Java程序员的地方:一个是CLASSPATH的问题,其实从原理上来说,是要搞清楚JRE的ClassLoader是如何加
- (转)专业的程序员需要具备的思考能力:写一个程序需要注意多少细节问题
- iOS开发的一个问题集