[转]JS跨域总结
本文转自:http://www.cnblogs.com/qixuejia/archive/2012/08/29/2662220.html
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
<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>
[转]JS跨域总结的更多相关文章
- 5种处理js跨域问题方法汇总(转载)
1.JSONP跨域GET请求 ajax请求,dataType为jsonp.这种形式需要请求在服务端调整为返回callback([json-object])的形式.如果服务端返回的是普通json对象.那 ...
- JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)
这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...
- 前端Js跨域方法汇总—剪不断,理还乱,是跨域
1.通过jsonp跨域2.通过修改document.domain来跨子域(iframe)3.隐藏的iframe+window.name跨域4.iframe+跨文档消息传递(XDM)5.跨域资源共享 C ...
- 【js跨域】js实现跨域访问的几种方式
这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...
- 【前端】【转】JS跨域问题总结
详情见原博客:详解js跨域问题 概念:只要协议.域名.端口有任何一个不同,都被当作是不同的域. 跨域资源共享(CORS) CORS(Cross-Origin Resource Sharing)跨域资源 ...
- js跨域访问,No 'Access-Control-Allow-Origin' header is present on the requested resource
js跨域访问提示错误:XMLHttpRequest cannot load http://...... No 'Access-Control-Allow-Origin' header is prese ...
- 利用JS跨域做一个简单的页面访问统计系统
其实在大部分互联网web产品中,我们通常会用百度统计或者谷歌统计分析系统,通过在程序中引入特定的JS脚本,然后便可以在这些统计系统中看到自己网站页面具体的访问情况.但是有些时候,由于一些特殊情况,我们 ...
- 三种方法实现js跨域访问
转自:http://narutolby.iteye.com/blog/1464436 javascript跨域访问是web开发者经常遇到的问题,什么是跨域,一个域上加载的脚本获取或操作另一个域上的文档 ...
- js跨域问题的解决
js提交请求给别的应用实例或者别的服务器,由于同源策略,存在js跨域的情况,我所知道两种处理方式: 1.jquery ajax+jsonp <script type="text/jav ...
- JS 跨域问题浅析及解决方法优缺点对比(转)
1.所谓 JS 跨域问题,是指在一个域下的页面中通过js访问另一个不同域下 的数据对象, 出于安全性考 虑,几乎所有浏览器都不允许这种跨域访问,这就导致在一些ajax应用中, 使用跨域的web ser ...
随机推荐
- javaSE阶段中 关于Sring类方法的应用
String类中有很多常用的方法,今天就一些方法涉及到的一些常见题 做两个小Demo 其中一个要求如下: 获取指定字符串中,大写字母.小写字母.数字 的个数 题目分析 * 为了统计大写字母.小写字 ...
- 解决.jsp及静态资源文件访问404的问题
我们在做Web项目时,经常将.jsp文件放到webapp\WEB-INF下,这时,我们访问jsp等文件的时候,就会报404. 如果是纯前后端分离的项目,后端只返回数据,不处理页面,也没问题.但,有时我 ...
- C#与数据库访问技术总结(三)之 Connection对象的常用方法
说明:前面(一)(二)总结了数据库连接的概念以及连接数据库的字符串中的各个参数的含义.这篇随笔介绍connection对象的常用方法. Connection对象的常用方法 Connection类型的对 ...
- UIPageViewController
前言 iPhone 和 iPad 都是通过页控件来展示多个桌面,很多 App 在第一次使用时也会使用页控件来介绍自己的功能,页控件的交互效果非常好,适用于把几个简单的页面充分展示出来. 1.UIPag ...
- centOS系统将php升级到5.6 安装扩展
在文章中,我们将展示在centOS系统下如果将php升级到5.6,之前通过yum来安装lamp环境,直接升级的话,提示没有更新包,也就是说默认情况下php5.3.3是最新 1.查看已经安装的php版本 ...
- Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装
[洛谷P2515][HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得 ...
- Glassfish Password Alias
https://docs.oracle.com/cd/E19798-01/821-1751/ghgqc/index.html
- opencv第二课,使用cmake编译OpenCV,并添加opencv_contrib模块
一.下载安装cmake 想要在Windows平台下生成OpenCV的解决方案,我们需要一个名为cmake的开源软件,可以在camke的官网:http://www.cmake.org/上下载到 或者点击 ...
- C. The Fair Nut and String 递推分段形dp
C. The Fair Nut and String 递推分段形dp 题意 给出一个字符串选择一个序列\({p_1,p_2...p_k}\)使得 对于任意一个\(p_i\) , \(s[p_i]==a ...
- mybatis和jdbc分析
从这个图上可以看出mybatis的整体执行图 jdbc的 mybatis对很多类型进行了转化,减少了开发的量