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代码)
Oct 29 Javascript
Jquery中dialog属性小记
Sep 03 Javascript
jquery和雅虎的yql服务实现天气预报服务示例
Feb 08 Javascript
javascript实现的元素拖动函数宿主为浏览器
Jul 21 Javascript
PHP守护进程实例
Mar 06 Javascript
浅谈toLowerCase和toLocaleLowerCase的区别
Aug 15 Javascript
bootstrap中模态框、模态框的属性实例详解
Feb 17 Javascript
jQuery实现的点击图片居中放大缩小功能示例
Jan 16 jQuery
JQuery事件委托原理与用法实例分析
May 13 jQuery
微信小程序如何自定义table组件
Jun 29 Javascript
使用axios请求时,发送formData请求的示例
Oct 29 Javascript
Vue + element 实现多选框组并保存已选id集合的示例代码
Jun 03 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
缓存技术详谈―php
2006/12/14 PHP
全局记录程序片段的运行时间 正确找到程序逻辑耗时多的断点
2011/01/06 PHP
PHP面向对象程序设计之接口的继承定义与用法详解
2018/12/20 PHP
JavaScript:new 一个函数和直接调用函数的区别分析
2013/07/10 Javascript
js与jQuery 获取父窗、子窗的iframe
2013/12/20 Javascript
解决json日期格式问题的3种方法
2014/02/02 Javascript
JS的数组迭代方法
2015/02/05 Javascript
跟我学习javascript的prototype原型和原型链
2015/11/18 Javascript
自己动手制作基于jQuery的Web页面加载进度条插件
2016/06/03 Javascript
Bootstrap Table的使用总结
2016/10/08 Javascript
jQuery表单插件ajaxForm实例详解
2017/01/17 Javascript
微信小程序 点击控件后选中其它反选实例详解
2017/02/21 Javascript
easyui combogrid实现本地模糊搜索过滤多列
2017/05/13 Javascript
微信小程序实现表单校验功能
2020/03/30 Javascript
React-Native之定时器Timer的实现代码
2017/10/04 Javascript
使用Vue完成一个简单的todolist的方法
2017/12/01 Javascript
JavaScript设计模式之构造器模式(生成器模式)定义与用法实例分析
2018/07/26 Javascript
vue中echarts图表大小适应窗口大小且不需要刷新案例
2020/07/19 Javascript
Python性能优化技巧
2015/03/09 Python
python 移除字符串尾部的数字方法
2018/07/17 Python
python实现抠图给证件照换背景源码
2019/08/20 Python
Django通用类视图实现忘记密码重置密码功能示例
2019/12/17 Python
Python request操作步骤及代码实例
2020/04/13 Python
Python Spyder 调出缩进对齐线的操作
2021/02/26 Python
澳大利亚在线批发商:Simply Wholesale
2021/02/24 全球购物
为什么需要版本控制
2016/10/28 面试题
面临毕业的毕业生自荐书范文
2014/02/05 职场文书
企业授权委托书范本
2014/04/02 职场文书
副科级后备干部考察材料
2014/05/15 职场文书
机关党员进社区活动总结
2014/07/05 职场文书
辞旧迎新演讲稿
2014/09/15 职场文书
2014年作风建设剖析材料
2014/10/23 职场文书
刮痧观后感
2015/06/05 职场文书
靠谱准确的求职信
2019/04/02 职场文书
大学生饮品店创业计划书范文
2019/07/10 职场文书
QT与javascript交互数据的实现
2021/05/26 Javascript