weidagang2046的专栏

物格而后知致
随笔 - 8, 文章 - 409, 评论 - 101, 引用 - 0
数据加载中……

服务器端可控情形的Javascript跨域访问解决方法

2006-12-5

 

我在最近的一个 web 项目中为了实现 bookmark 功能碰到了 javascript 跨域访问的问题。起初,在 google 上搜的很多解决方案并不适用于我的情形,只在有一篇文章中提到的远程加载 javascript 方法从理论上看到了解决的希望。但可惜作者只是一笔带过,并未用例子详细说明,所以不得不摸索了一阵才把这个问题搞定。在此,希望通过本文为同样被这个问题困扰的朋友们提供一个解决方法作为参考。如有错误,欢迎指正!

 

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 !但很快就会发现根本行不通。

 

跨域访问,简单来说就是 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 参数传给服务器。请看下面的代码:

 

var url = "http://localhost: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 方法每次提交的信息不能超过 2k

posted on 2006-12-05 22:48 weidagang2046 阅读(9260) 评论(11)  编辑  收藏

评论

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

IBM developerWorks上面有个文章,里面详细讲了ajax的三种数据传输机制,你上面这个实例就是其中的第三种方法。
教程文章地址:
http://www-128.ibm.com/developerworks/cn/views/xml/tutorials.jsp?cv_doc_id=110100
需要注册个ID才能阅读。
2006-12-06 09:27 | xinheqishi

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

我有个问题哦....
比如,我第一次发送的时候创建一个script对象,然后在很断的时间内发送了第二次,也就是创建了第二个script对象.那天他就把第一个覆盖了,第一个怎么办??

但我又不能创建很多个script对象,那样很占资源,只能删除一些对象,那样就又可能删除写没有反会的对象......

我的前提是我则个情求比较频繁..

希望能解我之惑...
email: zuan8888@gmail.com
2007-01-13 14:37 | 刹那

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

创建javascript对象的时候指定id属性可以避免覆盖;也可以按id查找对象来判断是否已经返回,如果找到的话就可以看情况删除。关于id的维护问题办法应该很多。比如,维护一个全局计数器。

如果一定要同步的话(比如,第一次返回才能发第二次),建议看看javascript的wait()函数。

ps: 我的javascript经验也不多,上面的建议还需要实践检验。欢迎交流!
2007-01-13 18:05 | weidagang2046

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

请问这种方式下客户端(浏览器端)和Bookmark servlet端之间的关系是不是和直接通过浏览器访问Bookmark servlet的关系是一样的? 因为我想用这个方法来解决一个问题,A网站(应该是相当于这里的Bookmark servlet)负责控制逻辑,B网站负责页面的外观显示.
客户端从B网站进入之后, 要动态创建javascript对象,提交多次请求, 而我想维护多个请求之间的状态关系;是否和直接通过浏览器访问B网站一样,维持session就OK了?

希望能解我之惑....谢谢!
2007-01-13 19:28 | sparklet

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

因为Bookmark Servlet对javascript一无所知,只当成一般的网页文本返回,所以我认为和一般浏览器的访问没有区别,用session维护状态是完全可以的。
2007-01-13 19:39 | weidagang2046

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

可行 跨域真是双刃剑
2007-02-04 11:42 | 小雨

# re: 服务器端可控情形的Javascript跨域访问解决方法[未登录]  回复  更多评论   

可以MSN交流吗?tangcaiyou@hotmail.com
2007-06-17 10:45 | eric

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

我尝试了类似的代码却没有成功。
我在一个A网站的portlet中,iframe了一个B网站的jsp页面,当点击该jsp的某个链接后,我需要将一个参数传送到A网站的某Servlet,可是没有成功。
代码如下:
site A的portlet:
从IFrame中的页面传来的参数:<%=portlet_a_s%>
<br/>
<iframe width="300" height="300" src="http://siteB:7001/myWeb/B.jsp">
</iframe>

site B的jsp:
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<html>
<head>
<title>
inner page
</title>

<script type="text/javascript">
var lastScript;
var h=document.getElementsByTagName("head")[0];

function loadScript(url){
var f=document.createElement("script");
var d=new Date().getTime();
f.type="text/javascript";
f.id=d;
f.src=url+'&date='+d;
document.body.appendChild(f);
if(lastScript&&g(lastScript))g(lastScript).parentNode.removeChild(g(lastScript));
lastScript=d;
}

function g(x){
return document.getElementById(x)
}

function onClickMeasureId(id){
var hidden = g("hidden_input");
hidden.value = id;
var url = "http://siteA:7001/testWeb/portlets/portlet_a/PortletAServlet?id="+id;
loadScript(url);
}

function onResponse(){
alert("response");
};
</script>
</head>
<body>
<a onclick="onClick('参数1')" href="#">参数1</a>
</body>
</html>

siteA的Servlet:
public class PorletAServlet extends HttpServlet
{
public void service(HttpServletRequest request,HttpServletResponse response){
if ( request.getParameter("id") != null ){
String id = request.getParameter("id").toString();
HttpSession session = request.getSession();
session.setAttribute("measure_id",request.getParameter("id") );
try{
response.setContentType("text/javascript");
PrintWriter out = response.getWriter();
out.write("onResponse();");
}
catch(Exception e){}
}
}
}

我执行siteA的portal,在siteA的servlet中加入断点,点击portlet中iframe中的链接,发行servlet并没有得到执行。实在不知道为何不成功。

不知道博主可否提供更加完整的例子?谢谢!
2007-06-22 14:57 | liao

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

@liao
你的例子应该没有大问题,应该调查servlet没有得到执行的原因。可以把url单独拷贝出来,敲到浏览器的地址栏中试试看servlet能否执行。我估计是url本身的问题,很可能没有真正对应到那个servlet。
2007-06-22 16:31 | weidagang2046@gmail.com

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

你好我 我碰到了一个问题

和你的说的类似

希望你帮我看下

多谢了 http://so.hr33.com/SearchResult.aspx?key=a&companyname=&zw=100&dq=100&sj=90&xl=10&jy=0&sex=2&age=0&yx=0&xz=0&hy=0&RCount=29&Page=1&type=1

你点申请后点关闭就会提示 "拒绝访问.."

MAIL 我 colvinliu@qq.com
2007-12-20 17:06 | colvinliu

# re: 服务器端可控情形的Javascript跨域访问解决方法  回复  更多评论   

转了一大圈 终于在这里找到了解决方法
2010-04-22 11:21 | 唐兵

只有注册用户登录后才能发表评论。


网站导航: