js前端解决跨域问题的8种方案(最新最全)


Posted in Javascript onNovember 18, 2016

1.同源策略如下:

URL 说明 是否允许通信
http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许
http://www.a.com/lab/a.jshttp://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 不同域名 不允许

特别注意两点:

第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,

第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。

“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。

2. 前端解决跨域问题

1> document.domain + iframe      (只有在主域相同的时候才能使用该方法)

1) 在www.a.com/a.html中:

document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){
 var doc = ifr.contentDocument || ifr.contentWindow.document;
 //在这里操作doc,也就是b.html
 ifr.onload = null;
};

2) 在www.script.a.com/b.html中:

document.domain = 'a.com';

2> 动态创建script

这个没什么好说的,因为script标签不受同源策略的限制。

function loadScript(url, func) {
 var head = document.head || document.getElementByTagName('head')[0];
 var script = document.createElement('script');
 script.src = url;

 script.onload = script.onreadystatechange = function(){
 if(!this.readyState || this.readyState=='loaded' || this.readyState=='complete'){
  func();
  script.onload = script.onreadystatechange = null;
 }
 };

 head.insertBefore(script, 0);
}
window.baidu = {
 sug: function(data){
 console.log(data);
 }
}
loadScript('http://suggestion.baidu.com/su?wd=w',function(){console.log('loaded')});
//我们请求的内容在哪里?
//我们可以在chorme调试面板的source中看到script引入的内容

3> location.hash + iframe

原理是利用location.hash来进行传值。

假设域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息。

1) cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面

2) cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据

3) 同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值

注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe

代码如下:

先是a.com下的文件cs1.html文件:

function startRequest(){
 var ifr = document.createElement('iframe');
 ifr.style.display = 'none';
 ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
 document.body.appendChild(ifr);
}

function checkHash() {
 try {
  var data = location.hash ? location.hash.substring(1) : '';
  if (console.log) {
   console.log('Now the data is '+data);
  }
 } catch(e) {};
}
setInterval(checkHash, 2000);

cnblogs.com域名下的cs2.html:

//模拟一个简单的参数处理操作
switch(location.hash){
 case '#paramdo':
  callBack();
  break;
 case '#paramset':
  //do something……
  break;
}

function callBack(){
 try {
  parent.location.hash = 'somedata';
 } catch (e) {
  // ie、chrome的安全机制无法修改parent.location.hash,
  // 所以要利用一个中间的cnblogs域下的代理iframe
  var ifrproxy = document.createElement('iframe');
  ifrproxy.style.display = 'none';
  ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata'; // 注意该文件在"a.com"域下
  document.body.appendChild(ifrproxy);
 }
}

a.com下的域名cs3.html

//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);

 4> window.name + iframe

window.name 的美妙之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

1) 创建a.com/cs1.html

2) 创建a.com/proxy.html,并加入如下代码

<head>
 <script>
 function proxy(url, func){
 var isFirst = true,
  ifr = document.createElement('iframe'),
  loadFunc = function(){
   if(isFirst){
   ifr.contentWindow.location = 'http://a.com/cs1.html';
   isFirst = false;
   }else{
   func(ifr.contentWindow.name);
   ifr.contentWindow.close();
   document.body.removeChild(ifr);
   ifr.src = '';
   ifr = null;
   }
  };

 ifr.src = url;
 ifr.style.display = 'none';
 if(ifr.attachEvent) ifr.attachEvent('onload', loadFunc);
 else ifr.onload = loadFunc;

 document.body.appendChild(iframe);
 }
</script>
</head>
<body>
 <script>
 proxy('http://www.baidu.com/', function(data){
  console.log(data);
 });
 </script>
</body>

3 在b.com/cs1.html中包含:

<script>
 window.name = '要传送的内容';
</script>

 5> postMessage(HTML5中的XMLHttpRequest Level 2中的API)

1) a.com/index.html中的代码:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
 var ifr = document.getElementById('ifr');
 var targetOrigin = 'http://b.com'; // 若写成'http://b.com/c/proxy.html'效果一样
          // 若写成'http://c.com'就不会执行postMessage了
 ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

2) b.com/index.html中的代码:

<script type="text/javascript">
 window.addEventListener('message', function(event){
  // 通过origin属性判断消息来源地址
  if (event.origin == 'http://a.com') {
   alert(event.data); // 弹出"I was there!"
   alert(event.source); // 对a.com、index.html中window对象的引用
         // 但由于同源策略,这里event.source不可以访问window对象
  }
 }, false);
</script>

6> CORS

CORS背后的思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

IE中对CORS的实现是xdr

var xdr = new XDomainRequest();
xdr.onload = function(){
 console.log(xdr.responseText);
}
xdr.open('get', 'http://www.baidu.com');
......
xdr.send(null);

其它浏览器中的实现就在xhr中

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
 if(xhr.readyState == 4){
  if(xhr.status >= 200 && xhr.status < 304 || xhr.status == 304){
   console.log(xhr.responseText);
  }
 }
}
xhr.open('get', 'http://www.baidu.com');
......
xhr.send(null);

实现跨浏览器的CORS

function createCORS(method, url){
 var xhr = new XMLHttpRequest();
 if('withCredentials' in xhr){
  xhr.open(method, url, true);
 }else if(typeof XDomainRequest != 'undefined'){
  var xhr = new XDomainRequest();
  xhr.open(method, url);
 }else{
  xhr = null;
 }
 return xhr;
}
var request = createCORS('get', 'http://www.baidu.com');
if(request){
 request.onload = function(){
  ......
 };
 request.send();
}

7> JSONP

JSONP包含两部分:回调函数和数据。

回调函数是当响应到来时要放在当前页面被调用的函数。

数据就是传入回调函数中的json数据,也就是回调函数的参数了。

function handleResponse(response){
 console.log('The responsed data is: '+response.data);
}
var script = document.createElement('script');
script.src = 'http://www.baidu.com/json/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);
/*handleResonse({"data": "zhe"})*/
//原理如下:
//当我们通过script标签请求时
//后台就会根据相应的参数(json,handleResponse)
//来生成相应的json数据(handleResponse({"data": "zhe"}))
//最后这个返回的json数据(代码)就会被放在当前js文件中被执行
//至此跨域通信完成

 jsonp虽然很简单,但是有如下缺点:

1)安全问题(请求代码中可能存在安全隐患)

2)要确定jsonp请求是否失败并不容易

8> web sockets

web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用)

web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为web sockt协议。

只有在支持web socket协议的服务器上才能正常工作。

var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
 var data = event.data;
}

 原文链接:http://blog.csdn.net/joyhen/article/details/21631833

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 常用代码技巧大收集
Feb 25 Javascript
jquery插件珍藏(图片局部放大/信息提示框)
Jan 08 Javascript
javascript操作表格排序实例分析
May 06 Javascript
js控制元素显示在屏幕固定位置及监听屏幕高度变化的方法
Aug 11 Javascript
js 自带的sort() 方法全面了解
Aug 16 Javascript
有关suggest快速删除后仍然出现下拉列表的bug问题
Dec 02 Javascript
使用JavaScript实现表格编辑器(实例讲解)
Aug 02 Javascript
浅谈让你的代码更简短,更整洁,更易读的ES6小技巧
Oct 25 Javascript
JS实现简单的点赞与踩功能示例
Dec 05 Javascript
JS插入排序简单理解与实现方法分析
Nov 25 Javascript
浅析 Vue 3.0 的组装式 API(一)
Aug 31 Javascript
微信小程序实现拼图小游戏
Oct 22 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
Nov 18 #Javascript
js实时获取窗口大小变化的实例代码
Nov 18 #Javascript
Kendo Grid editing 自定义验证报错提示的解决方法
Nov 18 #Javascript
整理一下常见的IE错误
Nov 18 #Javascript
require、backbone等重构手机图片查看器
Nov 17 #Javascript
基于touch.js手势库+zepto.js插件开发图片查看器(滑动、缩放、双击缩放)
Nov 17 #Javascript
移动端js图片查看器
Nov 17 #Javascript
You might like
浅谈json_encode用法
2015/03/05 PHP
php编程每天必学之表单验证
2016/03/01 PHP
浅谈PHP中的数据传输CURL
2016/09/06 PHP
php文件后缀不强制为.php的实操方法
2019/09/18 PHP
JavaScript原型链示例分享
2014/01/26 Javascript
SeaJS 与 RequireJS 的差异对比
2014/12/08 Javascript
JavaScript编写推箱子游戏
2015/07/07 Javascript
分享五个有用的jquery小技巧
2015/10/08 Javascript
JS实现简单的二维矩阵乘积运算
2016/01/26 Javascript
微信小程序 数据访问实例详解
2016/10/08 Javascript
Bootstrap如何创建表单
2016/10/21 Javascript
详解vue+vueRouter+webpack的简单实例
2017/06/17 Javascript
详解JS构造函数中this和return
2017/09/16 Javascript
微信小程序常见页面跳转操作简单示例
2019/05/01 Javascript
微信小程序里引入SVG矢量图标的方法
2019/09/20 Javascript
countup.js实现数字动态叠加效果
2019/10/17 Javascript
Swiper实现导航栏滚动效果
2020/10/16 Javascript
Python标准库之Sys模块使用详解
2015/05/23 Python
python导入csv文件出现SyntaxError问题分析
2017/12/15 Python
解决django中ModelForm多表单组合的问题
2019/07/18 Python
python实现提取str字符串/json中多级目录下的某个值
2020/02/27 Python
英国Amara家居法国网站:家居装饰,现代装饰和豪华礼品
2016/12/15 全球购物
美国网上眼镜供应商:LEOTONY(眼镜、RX太阳镜和太阳镜)
2017/10/31 全球购物
英国领先的高街书籍专家:Waterstones
2018/02/01 全球购物
老教师工作总结的自我评价
2013/09/27 职场文书
软件毕业生个人鉴定
2014/03/03 职场文书
药学职务聘任书
2014/03/29 职场文书
警示教育活动总结
2014/05/05 职场文书
建筑工地标语
2014/06/18 职场文书
销售人员工作自我评价
2014/09/21 职场文书
2014年敬老院工作总结
2014/12/08 职场文书
寒假安全保证书
2015/02/28 职场文书
开展警示教育活动总结
2015/05/09 职场文书
绿里奇迹观后感
2015/06/15 职场文书
办公室卫生管理制度
2015/08/04 职场文书
重温经典:乔布斯在斯坦福大学的毕业演讲(双语)
2019/08/26 职场文书