代码改变世界

【项目中遇到的问题】JavaScript 中的跨域访问方法(转)

2012-08-17 11:49  sniper007  阅读(297)  评论(0编辑  收藏  举报

JS中的跨域是受到限制的,但是跨域有时候又是必须的,藉此,各种高手牛人想尽办法使得JS能够跨域获取数据,有的方法真的很巧妙

在此记录一下常用的三种跨域方法,如下:

 

一、不同子域名之间的(a.example.com|b.example.com)的跨域访问。

  这种跨域调用比较常见,比如a.example.com 下的 a.htm 页面,需要调用 b.example.com 下的 b.htm页面里面的getData函数, 首先需要在a.htm页面中用iframe 框架把b.htm页面引用进来

<iframe id="b" src="http://b.example.com/b.htm" frameborder="on"></iframe>

然后同时在a.htm页面与b.htm页面中设置:document.domain = "example.com"; 这样a.htm就可以获取b.htm中的window documet 然后来获取b.htm中的数据getData了,获取b.htm中的document方法为:

function getIframeDocument(id){     returen document.getElementById(id).contentDocument || document.getElementById(id).document; }

 

二、不同域名之间的hash传递参数(www.a.com | www.b.com)

  常见的一个例子就是iframe自动适应大小,a域名下的a.htm 框架(iframe)了b域名中的b.htm,而b.htm的大小是不固定的,这时候就需要通过跨域传递b.htm的宽度与高度到a.htm中。

  这个参数是怎么传递的呢?是通过hash来传递的(www.b.com/b.htm#width|height)其中#号后面的参数width|height 即为window.location.hash的值

而改变hash的值也不会造成页面的跳转,但是这样还是跨域的,所以需要在a域下增加一个c.htm中间页面,这样c.htm与a.htm之间就是相同的域下,可以传递数

据,把c.htm页面通过iframe到b.htm中,由b.htm控制,看下图: 现在的关系为,a.htm中iframe加入了b.htm,b.htm页面中iframe加入了c.htm

 

  a.htm代码如下:


 
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Demo</title>
</head>
<body>
<div id="show">这是A域a</div>
<iframe id="b_iframe" src="http://www.b.com/b.htm" frameborder="on" border="1px" marginwidth="0" marginheight="0" scrolling="no" allowtransparency="yes" ></iframe>
</body>
</html>

 

 

b.htm代码如下:

 
<iframe id="c_iframe"  height="0" width="0"  src="http://www.a.com/c.htm" style="display:none" ></iframe>
<script type="text/javascript">
        
var b_width = Math.max(document.documentElement.clientWidth,document.body.clientWidth);
        
var b_height = Math.max(document.documentElement.clientHeight,document.body.clientHeight);
        console.log(b_width);
        
var c_iframe = document.getElementById("c_iframe");
        console.log(c_iframe.src);
        c_iframe.src 
= c_iframe.src + "#" + b_width + "|" + b_height;  // 这里通过hash传递b.htm的宽高
        /* http://www.b.com/c.html#width|height */

</script>

 

 

c.htm代码如下:

 
<script type="text/javascript">
        
var b_iframe = parent.parent.document.getElementById("b_iframe");//a与c是同域,可以通过parent获取到a.htm中的包含b.htm的框架的dom
        var hash_url = window.location.hash; //这里可以获取b.htm中传递过来的width|height        var hash_width = hash_url.split("#")[1].split("|")[0]+"px"; //分别获取值
        var hash_height = hash_url.split("#")[1].split("|")[1]+"px";
        console.log(
"hash_width=" + hash_width);
        console.log(
"hash_height=" + hash_height);

        b_iframe.style.width 
= hash_width; //a与c页面是同域,可以设置样式
        b_iframe.style.height = hash_height;</script>

 

 

这样就可以通过hash来传递数据,缺点是只支持string类型,大小受到限制!

 

三、通过jsonp来实现不通域名之间跨域传递数据。

什 么是jsonp(JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。如果要进行跨域请求,我们可以通过使用 html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象。这种跨域的通讯方式称为JSONP。)

  通俗来讲就是通过<script type="text/javascript" src="调用生成JS文件的地址并传递回调参数"></script> 来调用要执行的代码。

  也可以通过createElement('script')来生成,如下:  

var JSONP = document.createElement("script") ;//然后设置其src属性

  因为JS文件无论在什么地方都可以调用并执行,比如各种统计JS等,回调参数是怎么回事呢,就是告诉要传递数据的页面给把数据通过这个函数传递给我,大家

大家可以试一下下面这个地址:

http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?

上面的地址是flicker的API,其中的jsoncallback=? 中的问号替换成你自定义的回调函数,然后对方就会通过这个回调函数给你传递数据:

比如随便起名一个回调函数vvgcallback:

http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=vvgcallback

然后对方生成的js就是这样的(可以把以上地址复制到地址栏测试):

 
vvgcallback({
        "title": "Recent Uploads tagged cat",
        "link": "http://www.flickr.com/photos/tags/cat/",
        "description": "",
        "modified": "2012-08-15T06:07:40Z",
        "generator": "http://www.flickr.com/",
        "items": [
       {
            "title": "A squirell about to jump",
            "link": "http://www.flickr.com/photos/64477042@N00/7786494040/",
            "media": {"m":"http://farm9.staticflickr.com/8422/7786494040_a7a506dfdc_m.jpg"},
            "date_taken": "2012-08-10T15:19:40-08:00",
            "description": " <p><a href=\"http://www.flickr.com/people/64477042@N00/\">Dr arun kapoor<\/a> posted a photo:<\/p> <p><a href=\"http://www.flickr.com/photos/64477042@N00/7786494040/\" title=\"A squirell about to jump\"><img src=\"http://farm9.staticflickr.com/8422/7786494040_a7a506dfdc_m.jpg\" width=\"240\" height=\"191\" alt=\"A squirell about to jump\" /><\/a><\/p> <p><\/p>",
            "published": "2012-08-15T06:07:40Z",
            "author": "nobody@flickr.com (Dr arun kapoor)",
            "author_id": "64477042@N00",
            "tags": "barcelona china california birthday christmas city family flowers blue autumn friends england blackandwhite bw food dog baby india house holiday chicago canada black france flower color berlin green bird art fall film beach halloween church girl car fashion birds animals bike festival architecture clouds cat canon germany garden de geotagged fun graffiti hawaii dance football concert asia europe day florida band australia iphone instagramapp"
       },
       {
            "title": "catkeywest",
            "link": "http://www.flickr.com/photos/marshawheatley/7786461540/",
            "media": {"m":"http://farm8.staticflickr.com/7120/7786461540_5e3e28bd3a_m.jpg"},
            "date_taken": "2012-08-14T22:57:21-08:00",
            "description": " <p><a href=\"http://www.flickr.com/people/marshawheatley/\">MarshaWheatley<\/a> posted a photo:<\/p> <p><a href=\"http://www.flickr.com/photos/marshawheatley/7786461540/\" title=\"catkeywest\"><img src=\"http://farm8.staticflickr.com/7120/7786461540_5e3e28bd3a_m.jpg\" width=\"240\" height=\"180\" alt=\"catkeywest\" /><\/a><\/p> ",
            "published": "2012-08-15T06:08:53Z",
            "author": "nobody@flickr.com (MarshaWheatley)",
            "author_id": "85010317@N04",
            "tags": "old cat town florida keywest"
       }]
})

 

 

就相当与在页面执行vvgcallback()函数,括号中间的就是传递的JSON数据。这样就想当于在你的页面里面执行了以上的代码。从而实现了跨域传递数据。