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
						。