`
william_ai
  • 浏览: 21260 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

javascript的跨域请求

阅读更多
  • 扯淡

话说上个世纪60年代初,在美国加州的森尼维尔市,伴着他的第一声哭声,Brendan Eich开始了他的一生。和普通的孩子一样,他度过了快乐的童年,懵懂的青年时代,也顺利的读完了学士和硕士学位,开始了他程序员的生活。

毕业以后他在Silicon Graphics玩了7年的操作系统和网络编程(难道一个人公司的感情也会有7年之痒)。

离开了他的老东家之后,他来到了MicroUnity Systems Engineering,玩起了microkernel和DSP编程,也是在这时他第一次接触了MIPS架构的gcc R4000端口。

他在Netscape和Mozilla的时候达到了事业上巅峰。1995年4月,他开始玩起了Mocha,经过他一段时间的努力Mocha变得很强大了,于是在同年的9月,一个华丽的变身,更名为livescript并且第一次被装在Netscape Navigator 2.0里。在同年的12月4日,在与Sun公司的的联合声明中,livescript变身到最终形态,JavaScript神兵横空出世。

由于JavaScript神兵太过强大,人们给他加了封印。可是人总是有私心的,于是又留下了一些打开封印的办法。

淡扯完了,下面介绍下封印和如何解开封印。
Same origin policy
先说下封印跨域访问,javascript同源策略的限制,即a.com域名下的js无法操作b.com域名下的对象(跨域)。下面举了几个例子,看起来更形象一些。
URL 1URL 2是否允许通信备注
http://www.a.com/a.jshttp://www.a.com/b.js同域名
http://www.a.com/a.jshttp://www.a.com:8080/b.js同域名不同端口
http://www.a.com/a.jshttps://www.a.com/b.js同域名不同协议
http://www.a.com/a.jshttp://127.0.0.1/b.js域名与其IP
http://www.a.com/a.jshttp://www.b.com/b.js主域名子域名
http://www.a.com/a.jshttp://www.b.com/b.js不同域名

如果对Same origin policy还有什么不了解的可以到http://en.wikipedia.org/wiki/Same_origin_policy看下。

下面说下解开跨域访问这个封印的几个主要手印。

手印一JSONP,即JSON with Padding。由于封印同源策略的限制,跨域访问被封印了起来。如果需要解开封印进行跨域请求,得使用html的script标记,进行跨域请求,在response中,返回要执行的javascript代码、JSON对象等。这种解开封印进行跨域请求的方式称为JSONP。

如在www.a.com域名下有如下的html文件:
<html>
<head>
</head>
<body>
<script type="text/javascript" id="script1"></script>
<input type="text" id="a" name="a">
<input type="button" value="click" onclick="document.getElementById('script1').src='http://www.b.com/response.js'">
</body>
</html>

在www.b.com下的响应的response.js代码
var a=1;//设置变量
alert("Hello World");//调用函数
document.getElementById("a").value="Hello World";//设置表单

大多数时候,为了动态,我们是这么玩的。把www.a.com下的htm改成
<html>
<head>
</head>
<body>
<script type="text/javascript" id="script1"></script>
<input type="text" id="a" name="a">
<input type="button" value="click" onclick="document.getElementById('script1').src='http://www.b.com/response.jsp'">
</body>
</html>

把www.b.com/response.js改成response.jsp
<%out.print("var a=1;alert(\"Hello World\");document.getElementById(\"a\").value=\"Hello World\"");%>

虽然URL上看只多了一个p,但是手印JSONP却在解开封印的同时变得更具破坏力。

在手印JSONP的基础上,仙人YUI、Jquery、Dojo、Ext等纷纷研究出了自己的手印。

  • YUI

首先我们看看仙人YUI做了哪些工作。
YUI3.2的jsonp的使用方法如下(下面都是围绕YUI3.2分析的):
var url = "http://yuilibrary.com/gallery/api/random?callback={callback}";
function handleJSONP(response){//...};
//...
Y.jsonp(url,handleJSONP);
//...

ps:源码中examples/jsonp/jsonp_gallery.html有详细内容。
结印很快,调用很方便,下面看看是怎么实现的。
下载http://developer.yahoo.com/yui/3/,选择Full Developer Kit版,将yui_3.2.0.zip解压后,在yui/buil/jsonp目录下会看到6个文件:
jsonp.jsjsonp-debug.jsjsonp-min.js
jsonp-url.jsjsonp-url-debug.jsjsonp-url-min.js

主要看下jonp.js这个文件,在第8行
YUI.add('jsonp', function(Y) {
//...

为YUI这个function动态添加了一个叫jsonp的function。后面的代码中用到了大家耳熟能详的prototype,apply和unshift等JavaScript神兵的秘法,就不一一分析了,直接看第133行到137行之间的代码。
//...
        Y.Get.script(url, {
            onFailure: wrap(config.on.failure),
            onTimeout: wrap(config.on.timeout),
            timeout  : config.timeout
        });
//...

这里有个Y.Get.script(...)的调用,有url,onFailure,onTimeout和timeout参数,这个到底是做什么的呢?

看下yui/build/yui/get.js这个文件。
第30行到726行在做了一次漂亮的闭包的同时,给Y.Get赋了值。看下505行到725行,就会发现Y.Get大概长成这个样子
{
    PURGE_THRESH:20,
    _finalize:function(id){ ... },
    abort: function(o) { ... },
    script: function(url, opts) { return _queue("script", url, opts); },
    css: function(url, opts) { ... }
}

终于找到了上面提到的Y.Get.script这个function,可却发现里面另有洞天,还有个_queur(...)的调用,不入虎穴不得虎子,看看这个叫_queue的funciton里面到底有神马浮云。
跳到362行,找到了_queue的实现。不过别急,先看看上边353到361的注释
    /**
     * Saves the state for the request and begins loading
     * the requested urls
     * @method queue
     * @param type {string} the type of node to insert
     * @param url {string} the url to load
     * @param opts the hash of options for this request
     * @private
     */

说_queue对request的状态做了保存,而且开始load。好看代码吧。372行到378行和第389行的代码:
//...
        queues[id] = Y.merge(opts, {//这个merge的实现也很精彩的,在yui/build/yui/yui.js中。
            tId: id,
            type: type,
            url: url,
            finished: false,
            nodes: []
        });
//...
_next(id);
//...

发现实现了保存request的状态,也同时看出这里没有实现load的而是在第389行多了个_next(id)的调用。这个_next(...)到底是干什么的呢?(这个_next才是主角,要详细的分析分析)

//...
        d = w.document;
        h = d.getElementsByTagName("head")[0];
//...
        if (q.timeout) {
            // q.timer = L.later(q.timeout, q, _timeout, id);
            q.timer = setTimeout(function() { 
                _timeout(id);
            }, q.timeout);
        }
//...
            n = _scriptNode(url, w, q.attributes);
//...
        if (insertBefore) {
            //...
        } else {
            h.appendChild(n);
        }
//...

首先取document,然后领h只想head标签,n是通过_scriptNode再到_node,返回一个document.createElement("script"),在_node中通过一个漂亮的for(i in attr){ ... }循环完成了属性绑定。最后,如果没有指定insertBefore元素,那么就在head标签里,把上边创建的script标签append进去。

至此,仙人YUI的JSONP实现分析完毕。下面将要分析的是仙人Jqurey是怎么实现JSONP的。

  • Jquery

登录http://jquery.com/,选择DEVELOPMENT (179KB, Uncompressed Code)下载源码,这个看着比PRODUCTION (26KB, Minified and Gzipped)的要舒服些。

先看看在Jquery下JSONP怎么使用。往上的例子大多是用$.getJSON,而且介绍的很好。JE上有好多牛人写了具体的分析和实现过程。再写一个有人会审美疲劳,所以下面的例子用的是更为强悍的$.ajax({dataType:'script'...})。因为它加载的是一段script代码,而不仅仅是一个json。下面看看是怎么用的。
    $.ajax({
        url: "http://2520011.appspot.com/js/cross_domain_demo.js",//为了这个例子在GAE放了个测试的js
        dataType: 'script',
        success: function(data ){
            alert(data);
        }
    });

接口的api设计的也很方便,下面看看他是怎么实现的。

在源码5762行,我们找到了ajax的实现。跳过中间层层叠叠的无关代码,来到5859行,在这里柳暗花明了,我们终于找到了渴求已久的源码。
var head = document.getElementsByTagName("head")[0] || document.documentElement;
var script = document.createElement("script");
//...
script.src = s.url;
//...
head.insertBefore( script, head.firstChild );

算上插入就4行。。。Jquery真的够精简。牛人一般都这样吧,O(∩_∩)O哈哈~
到这里我们分析玩了仙人Jquery的实现,真的是一个比一个牛,下一段,我们一起分析下Dojo的实现。

to be continued......

ps:周一到周五每天至少一更,周末休息。
分享到:
评论
12 楼 mmtye 2011-01-06  
对于必须动态附加到文档的外部 js 文件,要保证动态引入的脚本全部执行完成后,才能执行后续代码。

可以将此部分代码封装后调用,如:

function loadJS (url, onload) {
	var domscript = document.createElement('script');
	domscript.src = url;
	if ( onload ) {
		domscript.onloadDone = false;
		domscript.onload = onload;
		domscript.onreadystatechange = function() {
			if ( "loaded" === domscript.readyState && domscript.onloadDone ) {
				domscript.onloadDone = true;
				domscript.onload();
				domscript.removeNode(true);
				}
		}
	}
	document.getElementsByTagName('head')[0].appendChild(domscript);
}
//执行加载外部 JS 文件
loadJS('a.js',function (){
	 loadJS('b.js',function (){
		loadJS('c.js',function (){
			alert('ok');
		});
 	});
});
11 楼 习惯在马桶上思考 2011-01-06  
jsonp不错,我们自己写了一个类似东西
10 楼 terryang 2011-01-06  
我都用jquert的跨域。下次试试这个。
9 楼 KimHo 2011-01-06  
extjs也封装了跨域访问,示例:
proxy: new Ext.data.ScriptTagProxy({
    url: 'http://extjs.com/forum/topics-remote.php'
})
8 楼 william_ai 2011-01-06  
哈哈,谢谢大家提的宝贵意见。
本贴旨在重温一下JSONP跨域访问方式。
也希望大家多多提出自己的宝贵建议和经验。
谢谢大家回帖。
7 楼 onlylau 2011-01-06  
通常采用iframe的方式来解决跨域问题
6 楼 onlylau 2011-01-06  
引用

JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。
JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

LZ可以看看这篇文章:http://kjah.iteye.com/blog/771797
5 楼 42087743 2011-01-06  
document.all 就是跨域? 也没有考虑浏览器兼容问题
4 楼 EldonReturn 2011-01-06  
几个跨域的比较不错的实现方案 (Dojo)

1. dojo/io/script
2. dojox/io/windowName
3 楼 faiinlove 2011-01-06  
看不懂,咋跨域了
2 楼 william_ai 2011-01-05  
qgymje 写道
这种方式有一个更专业的叫法:jsonp

大名叫JSON with Padding。
代码行数上比写个AJAX的实现要简单很多。而且是天生的异步。
1 楼 qgymje 2011-01-05  
这种方式有一个更专业的叫法:jsonp

相关推荐

    javascript跨域请求包装函数与用法示例.docx

    本文将深入探讨一个具体的JavaScript跨域请求包装函数,并通过示例来展示其实际应用。 #### 一、理解跨域请求 跨域请求是指在一个域名下的页面发起对另一个域名下的资源的请求。浏览器为了保护用户隐私和数据安全...

    JavaScript跨域请求库XDomain.zip

    XDomain 是 JavaScript CORS 跨域请求的一个替代产品,无需任何服务器端的配置。只需要在同域下放置一个 proxy.html 文件即可。该库利用 XHook 来获取所有 XHR,可以无缝的和其他库协同工作。 Features Simple ...

    javascript跨域请求包装函数与用法示例

    JavaScript跨域请求是Web开发中常见的一类问题,由于浏览器的同源策略限制,JavaScript不能直接访问不同源的资源。为了解决这个问题,开发者通常会使用JSONP(JSON with Padding)或CORS(Cross-Origin Resource ...

    cors-proxy:基于Java Jersey的CORS代理绕过javascript跨域请求限制

    cors-proxy 基于Java Jersey的CORS代理绕过javascript跨域请求限制关于由于浏览器实施的CORS限制,来自浏览器的Javascript无法访问来自其他域的资源。 该Web代理将绕过这些限制。环境Java 1.7以上Tomcat 7以上用法在...

    ajax跨域请求WebService.asmx

    【Ajax跨域请求WebService.asmx】是一个常见的Web开发技术应用场景,主要涉及到JavaScript的Ajax技术、C#编程语言以及ASP.NET的WebService组件。Ajax(Asynchronous JavaScript and XML)是一种在不刷新整个页面的...

    jsonpajax跨域请求

    总结,JSONP和CORS是解决JavaScript跨域问题的两种主要方法,它们各有优缺点,适用于不同的场景。JSONP简单易用,但安全性较低;CORS则更安全,但需要服务器端的配合。在实际开发中,根据项目需求和浏览器兼容性选择...

    Jquery跨域Ajax请求测试

    在Web开发中,由于同源策略的限制,JavaScript通常无法直接访问不同源的资源,但随着Web服务的广泛应用,跨域请求的需求日益增加。jQuery,作为一个强大的JavaScript库,提供了便捷的方式来处理这种问题,特别是通过...

    html通过 ajax jsonp跨域请求接收和传送数据

    **AJAX和JSONP跨域请求的实现过程** 1. **AJAX跨域**: 通常,AJAX请求受到同源策略限制。为实现跨域,我们可以使用CORS(Cross-Origin Resource Sharing)机制。服务器需要在响应头中添加`Access-Control-Allow-...

    ajax跨域请求demo.zip

    这个"ajax跨域请求demo.zip"压缩包提供了一个关于如何实现Ajax跨域请求的示例,涉及到前后端的交互。 首先,我们关注"前端代码"部分。前端通常使用JavaScript库如jQuery来实现Ajax请求。jQuery的`$.ajax()`方法是...

    解决ajax跨域请求问题

    然而,跨域请求是Ajax的一个常见问题,由于浏览器的同源策略限制,Ajax请求只能向与当前页面同源的服务器发送。本文将深入探讨如何解决Ajax跨域请求的问题。 首先,理解“同源策略”是解决问题的关键。同源策略是...

    Javascript跨域请求的4种解决方式

    跨域请求是指浏览器出于安全原因,对不同域之间的资源访问施加限制的行为。例如,当一个网页试图从另一个不同源(域名、协议或端口不同)加载资源时,就会触发跨域请求问题。 根据标题和描述的内容,我们需要探讨四...

    ajax处理跨域请求

    然而,随着互联网应用的发展,数据交互的需求日益增多,跨域请求成为一种常见的需求。AJAX(Asynchronous JavaScript and XML)技术允许我们在后台与服务器进行异步数据交换,而无需刷新整个页面。当使用AJAX进行...

    jQuery跨域请求,获取返回值

    然而,jQuery提供了一种跨域请求的方法,允许我们绕过这一限制,获取远程服务器的数据。这篇博客将探讨如何使用jQuery实现跨域请求以及如何获取返回值。 首先,我们需要理解什么是跨域请求。跨域请求是指一个域下的...

    ajax跨域请求

    ### AJAX跨域请求详解 #### 一、引言 在Web开发中,由于浏览器的同源策略限制,AJAX请求通常只能向同源服务器发送请求。然而,在实际应用中,跨域请求的需求非常常见。本篇文章将通过一个具体的示例(JSP页面+后台...

    Javascript跨域和Ajax跨域解决方案

    JavaScript跨域和Ajax跨域是Web开发中常见的问题,尤其在进行前后端分离或API调用时,由于浏览器的同源策略限制,不同域名、协议或端口的资源请求会被阻止,这就是所谓的“跨域”。本文将深入探讨JavaScript和Ajax...

    js跨域请求数据的3种常用的方法

    以上就是JavaScript跨域请求数据的三种常见方法。在实际开发中,选择哪种方法取决于项目需求、兼容性考虑以及服务器端的配合程度。对于需要复杂交互或安全性要求较高的场景,CORS可能是更好的选择;而对于简单的GET...

    arcgis api for javascript跨域处理方案

    ArcGIS API提供了一个内置的代理,名为"Resource Proxy",它允许开发者将敏感的服务或跨域请求路由到代理服务器,然后由代理服务器转发到实际的目标服务器。这样,浏览器将认为请求是在同一域内进行的,从而避免了...

    javascript跨域方案总结

    JavaScript跨域方案是Web开发中的一个重要主题,尤其是在构建现代Web应用程序时。由于浏览器的安全策略,JavaScript在不同域名之间默认不允许进行通信,这就是所谓的“同源策略”。然而,开发者经常需要在多个域之间...

Global site tag (gtag.js) - Google Analytics