首页IT科技js跨域请求有哪些方式可以使用(JavaScript跨域问题分析与总结_直来直往_百度空间)

js跨域请求有哪些方式可以使用(JavaScript跨域问题分析与总结_直来直往_百度空间)

时间2025-09-19 00:00:42分类IT科技浏览5497
导读:2009-11-15 16:44...

2009-11-15 16:44

一               、为什么需要JS跨域

假设我们构建了一个网上商城www.xxx.com               ,出于对用户账号安全性的考虑                        ,我们将用户登录统一到auth.xxx.com的子域下验证                。当一个未登录用户浏览商品以后点击购买        ,为了提高网站的用户体验           ,我们想提供一个无刷新的登录入口                       。我们立刻想到使用AJAX实现无刷新的数据交互                        ,可当我们实际使用AJAX向auth.xxx.com提交数据的时候            ,JS却出现错误提示       ,我们没有权限进行此操作                        ,因为XMLHTTPRequest的实现要遵循浏览器的安全模型的同源策略规则                ,JS只能往自己的同源(同协议                        、同域名        、同端口)发送XMLHTTPRequest请求   ,所以我们无法往子域发送AJAX请求        。 武汉百度公司

解决此问题的通常做法是由auth.xxx.com提供接口                       ,在www.xxx.com的域下做一个服务端代理            。但随着业务的发展                    ,我们又有a.xxx.com,b.xxx.com...等等都需要到auth.xxx.com做登录验证                   ,那么我们需要在每一个子域下都有一个服务端的Proxy                        ,值得庆幸的是这些子域都是我们自己的    ,对服务器上的程序有控制权               ,所以操作起来还是可行的                       。然而随着业务的继续发展                        ,我们有越来越多的合作伙伴        ,现在我们要与他们实现部分数据的跨域互通           ,那么我们就需要和他们去约定一大堆的接口                        ,然后自己逐一去实现Proxy            ,那么这种方式会带来很大的沟通和维护成本            。有没有更好的方式呢?有!那就是客户端的JS跨域方案        。

二           、浏览器端的JS跨域方案

无论是子域还是非子域       ,JAVASCRIPT本身并没有官方的跨域实现                        ,下面介绍的跨域方案都是开发者创造出来的巧妙的hack实现:

1                        、设置document.domain跨子域

2            、使用iframe的hash

3       、使用script标签

4                        、flash转发

上面各种方案的适用场景和开发成本也是不同的                ,你可以根据具体的情况来选择合适的跨域方案                       。

1                、设置document.domain

如果仅仅是要跨子域   ,那么最简单的方式是设置document.domain                       ,再配合隐藏的iframe                    ,然后通过下面的方式来完成异步请求                。

1.1 使用FORM提交

早期浏览器并不支持XMLHTTPRequest时,开发者就已经使用隐藏iframe和form的方式来做同源的异步数据提交                   ,原理就是iframe间的相互通信    。虽然我们现在是在子域间做异步数据提交                        ,但通过设置domain我们已经获取了子域iframe之间的控制权(需要注意的是并没有直接使用XMLHTTPRequest往auth子域下的页面发送异步请求的权限)    ,那么下面要做的工作和以前没有区别               ,这里就大概描述一下                        ,更具体的可以搜索下使用iframe做异步提交的资源                       。

我们在A页面(http://www.xxx.com/index.html)中以iframe形式插入一个auth子域下的B页面(http://auth.xxx.com/proxy.html)        ,并设置index.html和proxy.html页面的domain为xxx.com           ,这样index.html和proxy.html就有了互相访问的权限                   。

当用户在index.html输入登录信息提交时                        ,我们可以获取到用户输入的用户名和密码            ,然后我们把此信息写入到proxy.html页面中。通常我们会在proxy页面中放置一个form       ,然后把需要提交的数据写入到此form中再提交此form                        ,这样就完成了www到auth的数据提交                    。那我们怎么知道用户是否登录成功呢                ,我们需要一个反馈                       。proxy中的form对应的action页面接受到登录信息以后做验证   ,然后将反馈信息以JS脚本的形式输出                       ,例如document.domain=xxx.com;top.showLogin({code:0,user:yoyo});                    ,这样如果我们在index页面中定义了showLogin函数,那么用户登录以后就会自动调用                   ,并且接收都到了auth的登录反馈    。

1.2 使用XMLHTTPRequest提交 武汉百度推广

刚才我们是把数据通过proxy页面中的FORM提交出去的                        ,实际上现在的主流浏览器都已经支持XMLHTTPRequest    ,我们完全可以控制proxy页面实例化一个XMLHTTPRequest对象               ,那么这个实例是在proxy的域下的                        ,它是可以往auth.xxx.com提交AJAX请求的                。这和我们页面本身发送AJAX请求所不同的仅仅在于操作的window对象不同        ,如果我们把这个差异封装起来           ,那使用者也是感受不到其中的差异的                       。

2   、使用iframe的hash 同刚才的做法我们在A页面(http://www.xxx.com/index.html)中以iframe形式插入一个auth子域下的B页面(http://auth.xxx.com/proxy.html)                        ,但这次我们不需要设置document.domain            ,受安全策略的限制A页面的JS无法获取到A页面中iframe的src属性       ,更没有办法访问页面B中的元素                        ,但它可以设置iframe的src                ,假如A页面输入的用户名和密码同时以一定格式加入到了src对应的url中   ,例如:http://auth.xxx.com/proxy.html?user=yoyo&pwd=123456                       ,B页面是可以在GET信息中获取此登录信息做验证的        。这就完成了A到B的SET操作            。那B登录验证以后怎么给A反馈呢?同理                    ,我们可以在B页面以iframe形式引入一个www下的A_proxy页面(http://www.xxx.com/proxy.html),那么它也可以通过设置iframe的src的方式实现B到A_proxy的SET操作                   ,而A_proxy和A是一个域                        ,他们之间就可以自由地完成通信了                       。

如果我们把参数以GET的形式设置到iframe的src中    ,会造成iframe频繁发送请求            。为了避免这点               ,我们可以把参数以锚点的形式传入进入                        ,同时在iframe里对锚点的改变做一个监听即可        。那如何监听锚点的改变呢?

2.1:可以在iframe中使用setInterval频繁检查location.hash是否改变                       。如果你对你的代码效率有洁癖        ,那么你可以考虑使用下面的方法                。

2.2:在设置iframe的src的同时           ,改变一下iframe的width属性                        ,iframe内部使用onresize事件获知hash的改变    。

此方法不局限于跨子域的需求            ,在FaceBook的APP平台中       ,第三方应用的iframe的高度自适应就是采用此方法实现的(实际上iframe高度自适应没有A到B的set需求                        ,仅仅是B到A的set需求)                       。需要注意的是此方法的弊端在于做SET操作的时候受制于各个浏览器对url长度的限制                ,无法发送过多的数据                   。

3                       、使用script标签 武汉百度公司

当我们以script标签的src属性引入一个JS文件到页面中时   ,我们需要清楚下面两条规则:

3.1                    、文件下载完毕以后                       ,其中的JS会自动运行。

3.2、无论src来源的域是什么                    ,这段JS执行时信任的域都是此页面的域                    。

当用户登录的时候,A页面使用JS动态添加一个script节点到页面中                   ,并且把用户名和密码设置到src属性中                        ,例如:http://auth.xxx.com/login?user=yoyo&password=123456    ,那么完成了A到B的SET操作               ,当B做完验证以后                        ,把结果以JS形式返回过来        ,例如:showLogin({code:0,user:yoyo})                       。根据规则一这个JS函数会自动执行           ,如果我们在页面A中定义了showLogin的函数                        ,这就实现了B到A的回调反馈    。

此方法的经典应用就是JSONP            ,它在此核心功能的基础上有定义了一些规则:例如返回值都是JSON格式       ,script标签的src中引入一个callback参数指定回调函数名                。例如flickr的API                        ,http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=doSomething                ,返回的结果就是doSomething({JSON格式})   ,任何网站都可以通过JSONP调用此API来展示此照片列表                       。

在Jquery中也有getScript和getJSON的封装                       ,它隐藏了script标签和回调函数的动态创建                   、垃圾回收                        、非跨域情况下的浏览器阻塞(具体细节的实现也是很有意思的                    ,有空我会单独写一个分析),使用者只需要处理数据和回调函数即可        。

此方法不局限于跨子域的需求                   ,但由于它也是依赖设置script标签的src属性来做的set操作                        ,所以它同样受制于各个浏览器对url长度的限制    ,无法发送过多的数据            。

4    、flash转发 武汉百度推广

ACTIONSCRIPT本身也有发送异步请求的实现               ,虽然FlashPlayer也有安全域限制                        ,但相对于JS而言似乎更人性化                       。最初我由AS转入JS的时候就很诧异        ,同样是基于ECMAScript的实现           ,为何JS没有官方的跨域机制呢?首先简单讲一下FlashPlayer沙箱机制中的我们会用到的三个主要原则:

4.1               、FlashPlayer发送请求的时候也需要遵循浏览器的同源策略                        ,在早期版本中子域被视为安全域            ,但随着安全级别的提高       ,目前遵循的同源策略和JS一样                        ,只能往自己的同源(同协议                        、同域名        、同端口)发送请求            。如果需要往第三方的域发送请求                ,那么需要第三方在自己的server上放置一个crossdomain.xml的XML文件        。此文件就好比是一个白名单   ,可以设置自己信任的第三方域的访问                       。

4.2           、A域的页面引入了一个B域的Flash                       ,此Flash是无法和页面中的JS通信的                    ,需要A域页面在插入Flash的时候设置allowscriptaccess属性为B域(flash所在的域),或者是always(开放所有域)                。

4.3                        、A域的页面中的JS也无法访问B域的Flash                   ,需要Flash在脚本中通过allowDomain设置了A域为自己信任的安全域    。

了解了上面三个原则以后                        ,我们就可以解决A域页面和B域的flash的互相通信的问题    ,B域flash和A域的server通信的问题                       。下面介绍下Flash转发的实现原理:

用户交互还是由JS完成               ,当我们需要跨域发送请求的时候                        ,我们可以使用JS把数据传递给FLASH        ,然后由FLASH去跨域请求server           ,然后把server处理完毕的结果传递给js                   。具体实现主要是网络通信和回调函数                        ,需要特别注意的是FLASH和JS通信的时候            ,字符串中如果出现"\"       ,那么需要在AS内部对"\"做一次转义                        ,否则到了JS端此"\"会被当作转义符解析掉。

如果你是一个server端的程序员                ,你可能已经有一个疑惑了:真实的请求是由B域的flash发送的   ,如果我们的这个请求需要A域下的cookie信息怎么办呢?这里就需要提到一个FlashPlayer的奇妙"特性"                       ,无论flash的域在哪儿                    ,只要A域的server允许此域的flash访问,它向A域发送请求的时候                   ,都会把此时浏览器中属于A域的cookie一同发送过去                        ,因此"理论"上你不需要担心这个问题    ,但我需要提醒两点:

一            、这个特性仅限于URLRequest类               ,AS中的文件上传类就没有此特性                        ,相反它的实现让人感觉是残缺的        ,见"小心SWFUpload的cookie Bug"                    。

二       、在我项目中我曾经遇到过URLRequest类也丢失cookie的情况           ,但后来一直没有再重现                        ,我也无法排除当时有其他因素的影响            ,所以我刚才加了"理论"二字                       。如果你遇到了这个情况       ,也可以给我一个反馈                        ,一起交流一下    。现在我为了保险起见                ,我还是主动用JS把cookie获取   ,然后加入到flash的请求中                。

在Facebook的APP平台中有一个Fb:local-proxy的实现                       ,实际上核心就是Flash转发                    ,它的优势在于跨域没有局限,SET和GET操作也没有数据长度的局限                   ,劣势在于客户端需要依赖FLASH                        ,需要考虑的客户端复杂性                       。

测试环境部署麻烦    ,而且空余时间也有限               ,所以没有去写具体的示例代码                        ,上面写得还是很粗        ,见谅        。细节问题可以邮件                        、IM交流            。

声明:本站所有文章           ,如无特殊说明或标注                        ,均为本站原创发布                       。任何个人或组织            ,在未征得本站同意时       ,禁止复制                、盗用   、采集                       、发布本站内容到任何网站                    、书籍等各类媒体平台            。如若本站内容侵犯了原著者的合法权益                        ,可联系我们进行处理        。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
简述网站流量分析步骤及方法及步骤(简述网站中常见的流量分类) 域名查询结果(域名查终端成功率高的技巧)