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日历实现代码
Sep 12 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(二)人物行走的实现
Jan 23 Javascript
解析Javascript中难以理解的11个问题
Dec 09 Javascript
javascript实现页面刷新时自动清空表单并选中的方法
Jul 18 Javascript
easyui导出excel无法弹出下载框的快速解决方法
Nov 10 Javascript
socket.io学习教程之基础介绍(一)
Apr 29 Javascript
微信通过页面(H5)直接打开本地app的解决方法
Sep 09 Javascript
ES6解构赋值实例详解
Oct 31 Javascript
详解express使用vue-router的history踩坑
Jun 05 Javascript
微信小程序跳转到其他网页(外部链接)的实现方法
Sep 20 Javascript
初学vue出现空格警告的原因及其解决方案
Oct 31 Javascript
JS精确判断数据类型代码实例
Dec 18 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/03/04 日漫
用PHP和ACCESS写聊天室(七)
2006/10/09 PHP
Mysql中分页查询的两个解决方法比较
2013/05/02 PHP
php检测iis环境是否支持htaccess的方法
2014/02/18 PHP
php实现简单的上传进度条
2015/11/17 PHP
PHP中substr_count()函数获取子字符串出现次数的方法
2016/01/07 PHP
visual studio code 调试php方法(图文详解)
2017/09/15 PHP
jQuery 1.5最新版本的改进细节分析
2011/01/19 Javascript
用js通过url传参把数据从一个页面传到另一个页面
2014/09/01 Javascript
基于jQuery.Hz2Py.js插件实现的汉字转拼音特效
2015/05/07 Javascript
javascript创建函数的20种方式汇总
2015/06/23 Javascript
JS获取数组最大值、最小值及长度的方法
2015/11/24 Javascript
Javascript删除指定元素节点的方法
2016/06/21 Javascript
js实现图片左右滚动效果
2017/02/27 Javascript
使用vue-aplayer插件时出现的问题的解决
2018/03/02 Javascript
写一个移动端惯性滑动&amp;回弹Vue导航栏组件 ly-tab
2018/03/06 Javascript
vue自定义一个v-model的实现代码
2018/06/21 Javascript
Vue 中如何正确引入第三方模块的方法步骤
2019/05/05 Javascript
解决vue-cli@3.xx安装不成功的问题及搭建ts-vue项目
2020/02/09 Javascript
Linux中Python 环境软件包安装步骤
2016/03/31 Python
如何在Python函数执行前后增加额外的行为
2016/10/20 Python
python3实现跳一跳点击跳跃
2018/01/08 Python
Python3爬虫之urllib携带cookie爬取网页的方法
2018/12/28 Python
PyQt5+Pycharm安装和配置图文教程详解
2020/03/24 Python
css3和jquery实现自定义checkbox和radiobox组件
2014/04/22 HTML / CSS
简单整理HTML5的基本特性和语法
2016/02/18 HTML / CSS
会计岗位职责
2013/11/08 职场文书
公司端午节活动方案
2014/02/04 职场文书
共产党员承诺书
2014/03/25 职场文书
节电标语大全
2014/06/23 职场文书
汽车检测与维修专业求职信
2014/07/04 职场文书
施工安全协议书范本
2014/09/26 职场文书
土木工程专业本科生求职信
2014/10/01 职场文书
2014年社区卫生工作总结
2014/12/18 职场文书
JS异步堆栈追踪之为什么await胜过Promise
2021/04/28 Javascript
【海涛dota】偶遇拉娜娅 质量局德鲁伊第一视角解说
2022/04/01 DOTA