`
william_ai
  • 浏览: 20614 次
  • 性别: 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:周一到周五每天至少一更,周末休息。
分享到:
评论
32 楼 william_ai 2011-01-12  
bill.830420 写道
jsonp是好,但是弊端也是很明显的,楼主没有说,不能只说优点,不说缺点啊。期待楼主下面的更新。

稍后把他加进去。
31 楼 bill.830420 2011-01-11  
jsonp是好,但是弊端也是很明显的,楼主没有说,不能只说优点,不说缺点啊。期待楼主下面的更新。
30 楼 william_ai 2011-01-10  
在解决跨域问题的方法当中,JSONP解决JavaScript的跨域调用,iframe解决页面的嵌入(也有人用很复杂的方法实现JavaScript的调用),还有功能全面的Proxy。
场景方法
在www.a.com下,用www.b.com下的JavaScriptJSONP
在www.a.com下,嵌入www.b.com下的页面IFRAME
除以上两种场景外,还可以在www.a.com下,取得www.b.com下的documentPROXY
29 楼 tedeum 2011-01-10  
字很多,经常处理跨域问题,还没有一个很好的解决方案,收藏一下先
28 楼 william_ai 2011-01-10  
谢谢两位投良好的朋友支持我的帖子,同时也谢谢11位投隐藏的朋友百忙之中读了我的帖子,可是,能说下为什么隐藏么,有哪里写的不好或是不对地方?虚心求教,更好的把这个故事讲完。更希望读到这篇贴子的每位朋友也多提意见。
27 楼 zhangfengzfzfyn 2011-01-10  
快点更新阿。。。
26 楼 william_ai 2011-01-09  
看了两天的tzb,明天更新,哈哈
25 楼 dreamji 2011-01-08  
william_ai 写道
话说上个世纪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神兵太过强大,人们给他加了封印。可是人总是有私心的,于是又留下了一些打开封印的办法。

淡扯完了,下面介绍下封印和如何解开封印。

先说下封印跨域访问,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不同域名

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

手印一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做了哪些工作。
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参数,这个到底是做什么的呢?

to be continued......

24 楼 william_ai 2011-01-08  
ak121077313 写道
我没明白 怎么就跨域了。。。

原来的例子举的不好,现在做了下修改。
23 楼 ak121077313 2011-01-07  
我没明白 怎么就跨域了。。。
22 楼 william_ai 2011-01-07  
yvfish 写道
楼主讲故事可以,技术一般吧,呵呵

哈哈,我可是会骄傲的。我一直以为自己是在小学生水平上。

下面的思路是:
介绍一下动态创建script。
把Ext、Jquery,YUI的的源代码贴出来看看。
介绍下其他几种跨域访问方式,这里怕说多了收不住,弄得喧宾夺主,本末倒置就不好了。

关于内容安排上,大家多提宝贵建议啊。
21 楼 yvfish 2011-01-07  
楼主讲故事可以,技术一般吧,呵呵
20 楼 boygirl 2011-01-07  
我以前是用JSON格式的
19 楼 xingqiliudehuanghun 2011-01-07  
如果没有该死的IE浏览器,生活会变得很美好的。最起码在跨域这件事情上是这样,
一个postMessage就可以将众多烦人的事情搞定了
18 楼 william_ai 2011-01-07  
这个主要是出于安全性问题。
去年8月份左右还出了个node.js,可以在服务器端跑js代码。
javascript神兵太强大了,装个保险也是情有可原的。

主贴写的太不人道了,稍后我再补充些东西进去。O(∩_∩)O哈哈~
17 楼 code_k 2011-01-07  
如果跨域请求的那个服务器关闭了,或者网络不通了,这种异常,用jsonp可以捕获吗?
16 楼 superobin 2011-01-07  
我不喜欢jsonp是因为,需要后台在输出上与前台js耦合,我更倾向于数据与代码分离。虽然固定框架能把耦合减到最小。

哎,为了跨域没办法。。
规定跨域请求的人真是该死。。
15 楼 whaosoft 2011-01-07  
从这个贴中没看明白什么是跨域...
14 楼 william_ai 2011-01-07  
麦蒂粉丝 写道
'response.js'是自己写的一个js文件吗?

是的。在实现的时候,有2点要说明下。
1。response.js文件的后缀名不限于js,也可以是do, jsp, php, asp, aspx。
2。response.js可能是另外一个域里的。
13 楼 麦蒂粉丝 2011-01-06  
'response.js'是自己写的一个js文件吗?

相关推荐

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

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

    JavaScript跨域请求库XDomain.zip

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

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

    本文实例讲述了javascript跨域请求包装函数与用法。分享给大家供大家参考,具体如下: 一、源码 // 定义AJAX跨域请求的JSON (function(){ if(typeof window.$JSON== 'undefined'){ window.$JSON= {}; }; $JSON....

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

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

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

    假设域名是:http://www.example.com.cn/ 如果所请求的域名跟这个域名不致,这种情况就是跨域,由于跨域存在漏洞,所以一般来说正常的跨域请求方式是请求不到的。 解决方式: 一、window.name 1、 服务器返回 代码...

    跨域WebService请求-Nginx_SOAP服务_Ajax客户端.docx

    JavaScript安全性不允许POST的跨域请求(GET可以与服务器配合使用JSONP,有些勉强)。SOAP只能使用POST请求,所以无法直接跨域。一般的解决方案是使用服务器代理(由同域服务器跨域请求后返回),但导致过于复杂...

    JavaScript如何实现跨域请求

    什么是跨域请求? 简单的理解就是向不在同一个域名的服务器文件发出请求。这个还是用实际的例子来说明一下吧,比如baidu.com向cxyblog.com发送请求,这两个域名是不同的,那么这就是跨域了,出于安全性的考虑,这样...

    javascript跨域原因以及解决方案分享

    主要介绍了javascript跨域原因以及解决方案分享,十分的细致全面,有需要的小伙伴可以参考下。

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

    由于js同源策略的影响,当在某一域名下请求其他域名,或者同一域名,不同端口下的url时,就会变成不被允许的跨域请求。 那这个时候通常怎么解决呢,对此菜鸟光头我稍作了整理: 1.JavaScript  在原生js(没有jQuery...

    Springboot解决ajax+自定义headers的跨域请求问题

    由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器...接下来通过本文给大家介绍Springboot如何优雅的解决ajax+自定义headers的跨域请求 ,需要的朋友可以参考下

    JavaScript用JSONP跨域请求数据实例详解

    Javascript跨域访问是web开发者经常遇到的问题,什么是跨域,就是一个域上加载的脚本获取或操作另一个域上的文档属性。下面这篇文章主要介绍了JavaScript用JSONP跨域请求数据的方法,需要的朋友可以参考借鉴,下面来...

    跨域请求资源-jsonp和cors区别.pdf

    JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。那什么是跨域呢,简单地理解就是因为JavaScript同源策略的限制,a.com域名下的js无法操作b.com或是c.a.com域名下的对象。 当协议、子域名、主域名、...

    简单了解django处理跨域请求最佳解决方案

    一、什么是跨域请求 跨域: 简单来说就是 A 网站的 javascript 代码试图访问 B 网站,包括提交内容和获取内容。这显然是不安全的。为此,浏览器的鼻祖:网景(Netscape)公司提出了优秀的解决方案:著名的浏览器同源...

    通过jsonp获取json数据实现AJAX跨域请求

    它在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页,ajax 使用XMLHttpRequest对象在后台与服务器交换数据,XMLHttpRequest 是 AJAX 的基础,它允许客户端 JavaScript 通过 HTTP请求连接到远程服务器...

    【JavaScript源代码】解决vue $http的get和post请求跨域问题.docx

    解决vue $http的get和post请求跨域问题  vue $http的get和post请求跨域问题 首先在config/index.js中配置proxyTable proxyTable: { '/api':{ // target:'http://jsonplaceholder.typicode.com', target:'...

    jsonp:代理来帮助处理跨域请求

    启用对任何JSON API的跨域请求的HTTP代理。 有关文档,请参见 。 请参阅页面以获取更改日志。 发展 代码是结合JavaScript和TypeScript编写的。 该应用程序被编写为使用部署到 ,但可以通过执行以下操作在本地运行:...

    javascript 跨域问题以及解决办法

    javascript 跨域问题以及解决办法 什么是跨域问题? 跨域这个问题是由于浏览器的同源策略引起的,请求的URL地址,必须与浏览器的URL是相同协议、相同域名、相同端口的,否则是不允许访问的 浏览器URL 要访问的...

Global site tag (gtag.js) - Google Analytics