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 相关文章推荐
仅Firefox中链接A无法实现模拟点击以触发其默认行为
Jul 31 Javascript
js实现运动logo图片效果及运动元素对象sportBox使用方法
Dec 25 Javascript
jQuery中:file选择器用法实例
Jan 04 Javascript
jquery图片切换插件
Mar 16 Javascript
《JavaScript高级编程》学习笔记之object和array引用类型
Nov 01 Javascript
JavaScript实现下拉菜单的显示和隐藏
Jan 05 Javascript
JS获取地址栏参数的两种方法(简单实用)
Jun 14 Javascript
javascript对浅拷贝和深拷贝的详解
Oct 14 Javascript
vue2.X组件学习心得(新手必看篇)
Jul 05 Javascript
利用JQuery操作iframe父页面、子页面的元素和方法汇总
Sep 10 jQuery
vue超时计算的组件实例代码
Jul 09 Javascript
可拖拽组件slider.js使用方法详解
Dec 04 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
海贼王动画变成“真人”后,凯多神还原,雷利太帅了!
2020/04/09 日漫
深入探讨<br />和 \r\n两者有什么区别??
2013/06/05 PHP
PHP网络操作函数汇总
2015/05/18 PHP
Js setInterval与setTimeout(定时执行与循环执行)的代码(可以传入参数)
2010/06/11 Javascript
Jquery公告滚动+AJAX后台得到数据
2011/04/14 Javascript
jQuery的attr与prop使用介绍
2013/10/10 Javascript
javascript在子页面中函数无法调试问题解决方法
2014/01/17 Javascript
Node.js中使用计时器定时执行函数详解
2014/08/15 Javascript
JS访问SWF的函数用法实例
2015/07/01 Javascript
实例代码详解jquery.slides.js
2015/11/16 Javascript
Javascript实现图片懒加载插件的方法
2016/10/20 Javascript
input获取焦点时底部菜单被顶上来问题的解决办法
2017/01/24 Javascript
使用 vue.js 构建大型单页应用
2018/02/10 Javascript
jQuery实现文件编码成base64并通过AJAX上传的方法
2018/04/12 jQuery
小程序实现页面顶部选项卡效果
2018/11/06 Javascript
vue router 跳转时打开新页面的示例方法
2019/07/28 Javascript
node.js中process进程的概念和child_process子进程模块的使用方法示例
2020/02/11 Javascript
[01:10:27]DOTA2-DPC中国联赛正赛 SAG vs XG BO3 第二场 3月5日
2021/03/11 DOTA
Python实现获取域名所用服务器的真实IP
2015/10/25 Python
Python开发之快速搭建自动回复微信公众号功能
2016/04/22 Python
基于hashlib模块--加密(详解)
2017/06/21 Python
使用Python横向合并excel文件的实例
2018/12/11 Python
使用WingPro 7 设置Python路径的方法
2019/07/24 Python
python打包成so文件过程解析
2019/09/28 Python
Pycharm自动添加文件头注释和函数注释参数的方法
2020/10/23 Python
python3爬虫中多线程进行解锁操作实例
2020/11/25 Python
利用CSS3的flexbox实现水平垂直居中与三列等高布局
2016/09/12 HTML / CSS
利用CSS3实现开门效果实例源码
2016/08/22 HTML / CSS
HTML5 File API改善网页上传功能
2009/08/19 HTML / CSS
施华洛世奇英国官网:SWAROVSKI英国
2017/03/13 全球购物
ktv总经理岗位职责
2014/02/17 职场文书
小学生母亲节演讲稿
2014/05/07 职场文书
机械专业毕业生自我鉴定2014
2014/10/04 职场文书
2015年全国爱眼日活动方案
2015/05/05 职场文书
浅析Redis Sentinel 与 Redis Cluster
2021/06/24 Redis
php访问对象中的成员的实例方法
2021/11/17 PHP