JS跨域总结


Posted in Javascript onAugust 30, 2012

javascript跨域有两种情况:
1、基于同一父域的子域之间,如:a.c.com和b.c.com
2、基于不同的父域之间,如:www.a.com和www.b.com
3、端口的不同,如:www.a.com:8080和www.a.com:8088
4、协议不同,如:http://www.a.com和https://www.a.com
对于情况3和4,需要通过后台proxy来解决,具体方式如下:
a、在发起方的域下创建proxy程序
b、发起方的js调用本域下的proxy程序
c、proxy将请求发送给接收方并获取相应数据
d、proxy将获得的数据返回给发起方的js
发起方页面代码如下:

<form id="form1" runat="server"> 
<div> 
<input type="text" id="txtSrc" value="http://www.gzsums.edu.cn/webclass/html/html_design.html" style="width: 378px" /> 
<input id="btnProxy" type="button" value="通过Proxy获取数据" onclick="GetDataFromProxy();" /><br /> 
<br /> 
<br /> 
</div> 
<div id="divData"></div> 
</form> 
</body> 
<script language="javascript" type="text/javascript"> 
function GetDataFromProxy() { 
var src = document.getElementById('txtSrc').value; 
var request = null; 
if (window.XMLHttpRequest) { 
request = new XMLHttpRequest(); 
} 
else if (window.ActiveXObject) { 
request = new ActiveXObject("Microsoft.XMLHTTP"); 
} 
request.onreadystatechange = function() { 
var ready = request.readyState; 
var data = null; 
{ 
if (ready == 4) { 
data = request.responseText; 
document.getElementById('divData').innerHTML = data; 
} 
else { 
document.getElementById('divData').text = "Loading"; 
} 
} 
} 
var url = "Proxy.ashx?src=" + escape(src); 
request.open("get",url,false); 
request.send(null); 
} 
</script>

发起方Proxy代码如下:
using System.Data; 
using System.Linq; 
using System.Web; 
using System.Web.Services; 
using System.Web.Services.Protocols; 
using System.Xml.Linq; 
using System.IO; 
using System.Net; 
using System.Text; 
namespace WebApplication1 
{ 
/// <summary> 
/// Summary description for $codebehindclassname$ 
/// </summary> 
[WebService(Namespace = "http://tempuri.org/")] 
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
public class Proxy : IHttpHandler 
{ 
const int BUFFER_SIZE = 8 * 1024; 
public void ProcessRequest(HttpContext context) 
{ 
context.Response.ContentType = "text/plain"; 
string src = context.Request["src"]; 
WebRequest wr = WebRequest.Create(src); 
WebResponse wres = wr.GetResponse(); 
Encoding resEncoding = System.Text.Encoding.GetEncoding("gb2312"); 
StreamReader sr = new StreamReader(wres.GetResponseStream(), resEncoding); 
string html = sr.ReadToEnd(); 
sr.Close(); 
wres.Close(); 
context.Response.Write("<br/><br/><br/><br/>"); 
context.Response.Write(html); 
} 
public bool IsReusable 
{ 
get 
{ 
return false; 
} 
} 
} 
}

而情况1和2除了通过后台proxy这种方式外,还可以有7种办法来解决:
1、document.domain+iframe(只能解决情况1):
a、在发起方页面和接收方页面设置document.domain,并将值设为父域的主域名(window.location.hostname)
  b、在发起方页面创建一个隐藏的iframe,iframe的源是接收方页面
c、根据浏览器的不同,通过iframe.contentDocument || iframe.contentWindow.document来获得接收方页面的内容
d、通过获得的接收方页面的内容来与接收方进行交互
这种方法有个缺点,就是当一个域被攻击时,另一个域会有安全漏洞出现。
发起方页面代码如下:
<body> 
<div> 
<input type="text" id="txtSrc" value="http://b.a.com/DomainTest2.htm" style="width: 378px" /> 
<input id="btnDomain" type="button" value="通过Domain获取数据" onclick="GetDataFromDomain();" /><br /> 
<br /> 
<br /> 
</div> 
<div id="divData"></div> 
</body> 
<script language="javascript" type="text/javascript"> 
document.domain = 'a.com'; 
var src = document.getElementById('txtSrc').value; 
var ifr = document.createElement('iframe'); 
ifr.src = src; 
ifr.style.display = 'none'; 
document.body.appendChild(ifr); 
function GetDataFromDomain() { 
var doc = ifr.contentDocument || ifr.contentWindow.document; 
alert(doc.getElementById("data").value); 
} 
</script>

接收方页面代码如下:
<body> 
<input type="hidden" id="data" value="Cross Domain" style="width: 378px" /> 
</body> 
<script language="javascript" type="text/javascript"> 
document.domain = 'a.com'; 
</script>

2、动态创建script:
  a、在发起方页面动态加载一个script,script的URL指向接收方的一个处理地址(后台),该地址返回的javascript方法会被执行,另外URL中可以传入一些参数,该方法只支持GET方式提交参数。
  b、加载的script可以在调用跨域js方法后再做一些自己的处理
发起方页面的代码如下:
<head> 
<title>Script Test</title> 
<script language="javascript" type="text/javascript"> 
function load_script(callback){ 
var head = document.getElementsByTagName('head')[0]; 
var script = document.createElement('script'); 
var src = document.getElementById('txtSrc').value; 
script.type = 'text/javascript'; 
script.src = src; 
//借鉴了jQuery的script跨域方法 
script.onload = script.onreadystatechange = function(){ 
if((!this.readyState||this.readyState === "loaded"||this.readyState === "complete")){ 
callback && callback(); 
// Handle memory leak in IE 
script.onload = script.onreadystatechange = null; 
if ( head && script.parentNode ) { 
head.removeChild( script ); 
} 
} 
}; 
// Use insertBefore instead of appendChild to circumvent an IE6 bug. 
head.insertBefore( script, head.firstChild ); 
} 
</script> 
</head> 
<body> 
<input type="text" id="txtSrc" value="http://www.b.com/scripttest.aspx" style="width: 378px" /> 
<input type="button" value="通过动态创建script标签来获取数据" onclick="load_script(function(){alert('动态加载script标签成功')})"/> 
</body>

接收方服务器端代码如下:
protected void Page_Load(object sender, EventArgs e) 
{ 
Response.Clear(); 
Response.ContentType = "application/x-javascript"; 
Response.Write(String.Format(@"alert('{0}');", DateTime.Now)); 
Response.End(); 
}

3、location.hash+iframe:
  a、发起方创建一个隐藏的iframe,iframe的源指向接收方的页面,并通过接收方页面的hash值来传送数据
  b、发起方创建一个定时器,定时检查自己的location.hash并作相应的处理
c、接收方创建一个隐藏的iframe,iframe的源指向发起方所在域的一个代理页面,并将接收方根据发起方传入的数据而处理后的数据通过代理页面的hash值来传送
d、接收方创建一个定时器,定时检查自己的location.hash并作相应的处理
e、代理页面创建一个定时器,定时检查自己的location.hash并同步更新发起方页面的hash值
www.a.com/a.html#aaa,其中#aaa就是location.hash值
发起方页面代码如下:
<body> 
<div> 
<input type="text" id="txtSrc" value="1" style="width: 378px" /> 
<input id="btnAddHash" type="button" value="添加Hash值" onclick="addHash();" /> 
<iframe id="ifr1" style="display:none"></iframe> 
</div> 
</body> 
<script language="javascript" type="text/javascript"> 
function addHash() { 
var src = document.getElementById('txtSrc').value; 
if (src.length > 0) { 
changeHash(src); 
} 
} 
function changeHash(src) { 
if (document.getElementById('ifr1')) { 
var ifr = document.getElementById('ifr1'); 
ifr.src = 'http://www.b.com/Test/HashTest2.htm#' + src; 
} 
else { 
var ifr = document.createElement('iframe'); 
ifr.setAttribute('id', 'ifr1'); 
ifr.src = 'http://www.b.com/Test/HashTest2.htm#' + src; 
ifr.style.display = 'none'; 
document.body.appendChild(ifr); 
} 
} 
function checkHash() { 
if (location.hash && location.hash.length > 1) { 
changeHash(location.hash.substring(1)); 
} 
} 
setInterval(checkHash, 2000); 
</script>

接收方页面代码如下:
<body> 
<iframe id="ifr2" style="display:none"></iframe> 
</body> 
<script language="javascript" type="text/javascript"> 
function checkHash() { 
if (location.hash && location.hash.length > 1) { 
var hashData = location.hash.substring(1); 
var ifr = null; 
if (document.getElementById('ifr2')) { 
ifr = document.getElementById('ifr2'); 
} 
else { 
ifr = document.createElement('iframe'); 
ifr.setAttribute('id', 'ifr2'); 
ifr.style.display = 'none'; 
document.body.appendChild(ifr); 
} 
switch (hashData) { 
case '1': 
alert('One'); 
if (ifr) { 
ifr.src = 'http://www.a.com/test/HashTest3.htm#2'; 
} 
break; 
case '2': 
alert('Two'); 
if (ifr) { 
ifr.src = 'http://www.a.com/test/HashTest3.htm#1'; 
} 
break; 
default: 
break; 
} 
} 
} 
setInterval(checkHash, 2000); 
</script>

发起方域下的代理页面代码如下:
<body></body> 
<script language="javascript" type="text/javascript"> 
function checkHash() { 
if (parent && parent.parent && parent.parent.location && self.location.hash.length > 1) { 
parent.parent.location.hash = self.location.hash.substring(1); 
} 
} 
setInterval(checkHash, 500); 
</script>

4、window.name:
a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面
b、接收方在自己页面通过script将需要传送的数据放入window.name里
c、发起方在iframe的onload方法里将iframe的源改为和自己在同一个域下的代理页面(因为只能是同一个域下才能访问window.name的值)
d、获取window.name的值(虽然iframe的源改变了,但是window.name的值不会变)
window.name的值差不多可以有2MB大小
发起方页面代码如下:
<body> 
<div> 
<input id="btnName" type="button" value="通过window.name获取数据" onclick="getData();" /> 
<iframe id="ifr1" style="display:none" src="http://www.b.com/Test/NameTest2.htm"></iframe> 
</div> 
</body> 
<script language="javascript" type="text/javascript"> 
var ischanged = false; 
function changeSrc() { 
if (document.getElementById('ifr1')) { 
var ifr = document.getElementById('ifr1'); 
if (!ischanged) { 
ischanged = true; 
ifr.contentWindow.location = 'http://www.a.com/Test/NameTest3.htm'; 
} 
else { 
var data = ifr.contentWindow.name; 
alert(data); 
} 
} 
else { 
var ifr = document.createElement('iframe'); 
ifr.setAttribute('id', 'ifr1'); 
ifr.src = 'http://www.b.com/Test/NameTest2.htm'; 
ifr.style.display = 'none'; 
document.body.appendChild(ifr); 
} 
} 
function getData() { 
setInterval(changeSrc, 2000); 
} 
</script>

接收方页面代码如下:
<body></body> 
<script language="javascript" type="text/javascript"> 
window.name = 'NameTest2'; 
</script>

发起方域下的代理页面代码如下:
<body></body>
(其实什么都不用写)
5、HTML5的postMessage
a、receiverWindow.postMessage(msg, targetOrigin),receiverWindow就是对接收消息的window的引用,可以是iframe的contentWindow/window.open的返回值/window.frames中的一个;msg就是要发送的消息,string类型;targetOrigin用于限制receiverWindow的URI,包括主域名和端口,使用“*”表示无限制,但是为了安全起见还是需要设置下,以防把消息发送给恶意的网站,如果targetOrigin的URI和receiverWindow的不符,则放弃发送消息。
b、接收方通过message事件来获得消息,并且通过event.origin的属性来验证发送方并通过event.data来获得传送的消息内容,event.source来获得发送方的window对象
发起方页面代码如下:
<body> 
<div> 
<input id="btnPostMessage" type="button" value="通过PostMessage获取数据" onclick="getData();" /> 
<iframe id="ifr" style="display:none" src="http://www.b.com/Test/PostMessageTest2.htm"></iframe> 
</div> 
</body> 
<script language="javascript" type="text/javascript"> 
function getData() { 
var ifr = document.getElementById('ifr'); 
var targetOrigin = 'http://www.b.com'; 
if (ifr.contentWindow.postMessage) { 
ifr.contentWindow.postMessage('PostMessageTest2', targetOrigin); 
} 
} 
</script>

接收方页面代码如下:
<body></body> 
<script language="javascript" type="text/javascript"> 
window.addEventListener('message', function(event) { 
if (event.origin == 'http://www.a.com') { 
alert(event.data); 
alert(event.source); 
} 
}, false); 
</script>

6、window.opener(适用于IE6、7,也就是operner hack方法,不过貌似现在已经不管用了,只要打过微软的安全补丁.kb2497640就不能用了)
  a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面
b、发起方页面通过iframe.contentWindow.opener = {a: function(params){...}, b: function(params){...} ...}来定义可被接收方调用的方法
c、接收方页面通过window.opener.a/window.opener.b来调用发起方定义的方法
d、接收方页面通过parent.opener = {c: function(params){...}, d: function(params){...} ...}来定义可被发起方调用的方法
e、发起方页面通过opener.c/opener.d来调用接收方定义的方法
其实原理就是重置opener对象
发起方页面代码如下:
<body> 
<iframe id="ifr" src="http://www.b.com/test/OpenerTest2.htm" style="display:none"></iframe> 
</body> 
<script language="javascript" type="text/javascript"> 
var ifr = document.getElementById('ifr'); 
ifr.contentWindow.opener = { a: function(msg) { alert('我调用了a方法获得了消息:' + msg); } } 
</script>

接收方页面代码如下:
<body> 
</body> 
<script language="javascript" type="text/javascript"> 
window.opener.a('aaa'); 
</script>

7、window.navigator(适用于IE6、7,貌似现在还能用,还没被补丁掉)
a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面
b、发起方页面通过window.navigator.a = function(params){...}; window.navigator.b = function(params){...}; 来定义被接收方调用的方法
c、接收方页面通过window.navigator.a(params); window.navigator.b(params);来调用发起方定义的方法
d、接收方页面通过window.navigator.c = function(params){...}; window.navigator.d = function(params){...}; 来定义被发起方调用的方法
e、发起方页面通过window.navigator.c(params); window.navigator.d(params);来调用接收方定义的方法
发起方页面代码如下:
<body> 
<iframe id="ifr" src="http://www.b.com/test/NavigatorTest2.htm" style="display:none"></iframe> 
</body> 
<script language="javascript" type="text/javascript"> 
window.navigator.a = function(msg) { alert('我调用了a方法获得了消息:' + msg); } 
window.navigator.b = function(msg) { alert('我调用了b方法获得了消息:' + msg); } 
setInterval(function() { window.navigator.c('ccc'); }, 2000); 
setInterval(function() { window.navigator.d('ddd'); }, 2000); 
</script>

接收方页面代码如下:
<body> 
</body> 
<script language="javascript" type="text/javascript"> 
window.navigator.c = function(msg) { alert('我调用了c方法获得了消息:' + msg); } 
window.navigator.d = function(msg) { alert('我调用了d方法获得了消息:' + msg); } 
setInterval(function() { window.navigator.a('aaa'); }, 2000); 
setInterval(function() { window.navigator.b('bbb'); }, 2000); 
</script>
Javascript 相关文章推荐
JavaScript 常见对象类创建代码与优缺点分析
Dec 07 Javascript
基于jQuery实现的百度导航li拖放排列效果,即时更新数据库
Jul 31 Javascript
js跑步算法的实现代码
Dec 04 Javascript
通过js为元素添加多项样式,浏览器全兼容写法
Aug 30 Javascript
jQuery中使用each处理json数据
Apr 23 Javascript
Javascript点击按钮随机改变数字与其颜色
Sep 01 Javascript
javascript 中iframe高度自适应(同域)实例详解
May 16 Javascript
Javascript中弹窗confirm与prompt的区别
Oct 26 Javascript
从源码里了解vue中的nextTick的使用
Nov 22 Javascript
详解js创建对象的几种方法及继承
Apr 12 Javascript
jquery实现直播视频弹幕效果
Feb 25 jQuery
js实现特别简单的钟表效果
Sep 14 Javascript
js中判断Object、Array、Function等引用类型对象是否相等
Aug 29 #Javascript
xml转json的js代码
Aug 28 #Javascript
基于jquery创建的一个图片、视频缓冲的效果样式插件
Aug 28 #Javascript
javascript 判断中文字符长度的函数代码
Aug 27 #Javascript
Jquery 数据选择插件Pickerbox使用介绍
Aug 24 #Javascript
javascript数字格式化通用类 accounting.js使用
Aug 24 #Javascript
jquery动画4.升级版遮罩效果的图片走廊--带自动运行效果
Aug 24 #Javascript
You might like
3.从实例开始
2006/10/09 PHP
PHP实现清除MySQL死连接的方法
2016/07/23 PHP
MAC下通过改apache配置文件切换php多版本的方法
2017/04/26 PHP
PHP简单留言本功能实现代码
2017/06/09 PHP
Laravel学习教程之View模块详解
2017/09/18 PHP
JQUERY设置IFRAME的SRC值的代码
2010/11/30 Javascript
常用js字符串判断方法整理
2013/10/18 Javascript
JavaScript优化专题之Loading and Execution加载和运行
2016/01/20 Javascript
javascript实现的左右无缝滚动效果
2016/09/19 Javascript
如何使用headjs来管理和异步加载js
2016/11/29 Javascript
如何在AngularJs中调用第三方插件库
2017/05/21 Javascript
详解Angular2组件之间如何通信
2017/06/22 Javascript
JavaScript之创意时钟项目(实例讲解)
2017/10/23 Javascript
javascript实现循环广告条效果
2017/12/12 Javascript
解决npm管理员身份install时出现权限的问题
2018/03/16 Javascript
Vue 全局loading组件实例详解
2018/05/29 Javascript
JS html事件冒泡和事件捕获操作示例
2019/05/01 Javascript
JS实现数组删除指定元素功能示例
2019/06/05 Javascript
[48:20]OpTic vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
pyramid配置session的方法教程
2013/11/27 Python
用Python实现一个简单的多线程TCP服务器的教程
2015/05/05 Python
Python 专题三 字符串的基础知识
2017/03/19 Python
Python使用struct处理二进制的实例详解
2017/09/11 Python
Python之pandas读写文件乱码的解决方法
2018/04/20 Python
OpenCV+python手势识别框架和实例讲解
2018/08/03 Python
python 使用re.search()筛选后 选取部分结果的方法
2018/11/28 Python
python判断所输入的任意一个正整数是否为素数的两种方法
2019/06/27 Python
使用PyTorch将文件夹下的图片分为训练集和验证集实例
2020/01/08 Python
Java多线程实现四种方式原理详解
2020/06/02 Python
Python3爬虫发送请求的知识点实例
2020/07/30 Python
英国高级百货公司:Harvey Nichols
2017/01/29 全球购物
车库门开启器、遥控器和零件:Chamberlain
2019/04/09 全球购物
爱护公共设施倡议书
2014/08/29 职场文书
五年级小学生评语
2014/12/26 职场文书
祝寿主持词
2015/07/02 职场文书
python实现简单区块链结构
2021/04/25 Python