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
。