服务器端可控JS跨域访问解决方法

来源:互联网 发布:数据恢复软件破解版 编辑:程序博客网 时间:2024/05/22 01:29

我在最近的一个 web 项目中为了实现 bookmark 功能碰到了 javascript 跨域访问的问题。起初,在 google 上搜的很多解决方案并不适用于我的情形,只在有一篇文章中提到的远程加载 javascript 方法从理论上看到了解决的希望。    
希望通过本文为同样被这个JS跨域访问问题困扰的朋友们提供一个JS跨域访问解决方法作为参考。如有错误,欢迎指正!   
Bookmark 是目前许多 web2.0 网站 (http://del.icio.us/, www.diigo.com 等)都提供的热门 feature 。它能将互联网上自己喜欢的网页收藏到 Bookmark 服务器上。本文要解决的问题就发生在用户提交网页 URL (还包括 Tag, Notes 等)给 Bookmark 服务器时。   
关于 URL 的提交至少可以有三种方式:   
1. 登陆 Bookmark 服务器的提交页面,将要收藏的 URL 通过该页面提交给服务器。   
2. 安装浏览器插件,通过插件将 URL 提交给服务器。   
3. 从 Bookmark 服务器动态加载 javascript 小工具到当前页面,通过它来完成提交工作。(参考 diigo 的例子,收藏一个网页链接到浏览器收藏夹,链接的 URL 是一段 javascript 代码,它会从服务器加载一段 javascript 注入当前网页)   

第一种方式开发起来最简单,但对用户来讲比较麻烦,每次都需要先登陆 Bookmark 服务器才能完成提交;
第二种方式我并不熟悉插件开发,而且用户也不喜欢太多的插件堆满自己的浏览器;
第三种方式开发难度小,又避免了每次登陆服务器的麻烦,所以我最终采用了它。   

上面讲的第三种方式中动态加载的 javascript 小工具除了需要生成 UI 供用户填写信息( URL , tag , notes 等),当用户点击提交的时候,还要完成与服务器通信的功能。在没有跨域访问经验的情况下,最先想到的当然是 ajax !但很快就会发现根本行不通。   
JS跨域访问,简单来说就是 A 网站的 javascript 代码试图访问 B 网站,包括提交内容和获取内容。由于安全原因,跨域访问是被各大浏览器所默认禁止的。写过跨域访问 ajax 的朋友相信都遇到过被告知“没有权限”的情况。通过 XMLHttp 来发送数据给 Bookmark 服务器的尝试失败了。于是,看到网上的一些资料,我又开始尝试用 javascript 小工具在用户网页动态创建一个隐藏的 iframe, iframe 的 src 指向服务器的一个 servlet ,试图通过调用 iframe 中提供的 javascript 来完成与服务器的通信。但不幸的是,用户网页中的 javascript 代码访问 iframe 也被浏览器归为跨域访问(特指 iframe 的 src 指向其它网站的情形),尝试再次失败。

最终,在一篇文章中看到,与 iframe 不同,如果 A 网站从 B 网站加载 javascript , A 网站可以自由的访问该 javascript 的内容,并不会被浏览器认为是跨域访问。模仿刚才 iframe 的思路,当用户点击提交时,可以动态创建一个 javascript 对象,该对象的 src 指向 Bookmark 服务器的一个 servlet ,注意: URL 、 Tag 、 Notes 、 User 、 Password 等信息被作为 src URL 参数传给服务器。请看下面的代码JS跨域访问解决方法:

复制内容到剪贴板
代码:
var url = "http://bbs.ad0.cn:8080/Deeryard/BookmarkServlet?" + "url=" + url_source + "&" + "title=" + title + "&" + "tag=" + tag + "&" + "notes=" + notes + "&" + "user=" + user + "&" + "password=" + password;   
url = encodeURI(url);   
//Submit to server with a trick   
var js_obj = document.createElement( "script" );   
js_obj.type = "text/javascript" ;   
js_obj.setAttribute( "src" , url);   
//Get response from server by appending it to document   
document.body.appendChild(js_obj);

上面例子中, js_obj.setArrribute() 将信息作为 src 的 URL 参数提交给了 Bookmark servlet 。那么用户又如何取得服务器的响应信息呢?答案就是最末一行代码, servlet 的输出必须是 javascript 代码,它可以调用用户网页上的其他 javascript 函数,以及操作 dom 对象。下面的 servlet 代码生成了一个 javascript 函数调用:   
out.write("onServerResponse(INADEQUATE_INFORMATION);");   
document.body.appendChild(js_obj) 执行后 onServerResponse( INADEQUATE_INFORMATION) 就会得到执行,使客户网页响应服务器结果。这样一个完整的通信过程就完成了。   

来总结一下这个案例,首先与很多跨域访问的情形不同,本文提到的跨域访问需要对服务器端进行控制,即让服务器端 Servlet 来适应客户端网页 javascript 的需求;而其他一些常见的例子则对服务器端没有控制能力,比如从其他网站抓内容的小偷程序。另外,需要注意的是这种方法中实际用到了 get 方法来提交信息,从一些资料上看到, get 方法每次提交的信息不能超过。
===================================================================================================================

两个应用系统的页面之间需要用javascript交互,一般情况下比如子页面调用父页面的操作window.parent....这时会抛出一个javascirpt错误,提示没有权限。
实际这是浏览器禁止了javascript域访问。

今天测试了一下,发现如果在一个应用服务器下发布的两个应用,链接的url只是在路径上有不同,比如http://localhost:8080/proXX,这样的两个应用界面可以相互调用。

如果不在同一应用下就有以下的方式:
1、设置document.domain
前提条件:两个页面同属于一个基础域(例如都是tb.com);同一协议(例如都是http);同一端口(例如都是80)。
方法:设置两个页面的document.domain都设置为自己所在的基础域名。
例子:a.tb.com里面的一个页面需要调用b.tb.com里的一个对象,则将两个页面的document.domain都设置为tb.com,就可以了。

document.domain 的使用和需要注意的
在 JavaScript 中我们可以通过在页面中加入如下声明来强制指定页面所属的域。
<script language="JavaScript">
<!--
document.domain = "tb.com"; //指定 document 所属的域
-->
</script>
document.domain 属性是不可以随便设置的,它只能被设置为文件所属域的上级域。
只有当两个域存在相同的上级域时,才能通过指定 document.domain 来实现它们之间的数据交换,并且 document.domain 属性必须被 设置为二者的公共域。
并非所有的浏览器都支持对 document.domain 属性进行设置。如 MSIE 和 Netscape 它们4.0以前的版本是不支持对该属性的设置的;另外有趣的是虽然 Netscape 在4.0以后开始支持对 domain 进行设置了,但在4.03 和4.04两个版本中 Netscapre 居然又把上面的功能给取消了。

2、在服务器端设置代理(所谓的小偷程序)
域的请求同样发送到本地服务器端,由服务器端的代理来请求相应的数据,然后发送给浏览器端。这样实际上浏览器端的所有请求都是发到相同的域,在服务器端代理的帮助下,实现了域的能力。

原创粉丝点击