服務(wù)器端可控情形的Javascript跨域訪問解決方法
我在最近的一個(gè)
web
項(xiàng)目中為了實(shí)現(xiàn)
bookmark
功能碰到了
javascript
跨域訪問的問題。起初,在
google
上搜的很多解決方案并不適用于我的情形,只在有一篇文章中提到的遠(yuǎn)程加載
javascript
方法從理論上看到了解決的希望。但可惜作者只是一筆帶過,并未用例子詳細(xì)說明,所以不得不摸索了一陣才把這個(gè)問題搞定。在此,希望通過本文為同樣被這個(gè)問題困擾的朋友們提供一個(gè)解決方法作為參考。如有錯(cuò)誤,歡迎指正!
Bookmark
是目前許多
web2.0
網(wǎng)站
(http://del.icio.us/, www.diigo.com
等)都提供的熱門
feature
。它能將互聯(lián)網(wǎng)上自己喜歡的網(wǎng)頁收藏到
Bookmark
服務(wù)器上。本文要解決的問題就發(fā)生在用戶提交網(wǎng)頁
URL
(還包括
Tag, Notes
等)給
Bookmark
服務(wù)器時(shí)。
關(guān)于
URL
的提交至少可以有三種方式:
1.??????
登陸
Bookmark
服務(wù)器的提交頁面,將要收藏的
URL
通過該頁面提交給服務(wù)器。
2.??????
安裝瀏覽器插件,通過插件將
URL
提交給服務(wù)器。
3.??????
從
Bookmark
服務(wù)器動態(tài)加載
javascript
小工具到當(dāng)前頁面,通過它來完成提交工作。(參考
diigo
的例子,收藏一個(gè)網(wǎng)頁鏈接到瀏覽器收藏夾,鏈接的
URL
是一段
javascript
代碼,它會從服務(wù)器加載一段
javascript
注入當(dāng)前網(wǎng)頁)
第一種方式開發(fā)起來最簡單,但對用戶來講比較麻煩,每次都需要先登陸
Bookmark
服務(wù)器才能完成提交;第二種方式我并不熟悉插件開發(fā),而且用戶也不喜歡太多的插件堆滿自己的瀏覽器;第三種方式開發(fā)難度小,又避免了每次登陸服務(wù)器的麻煩,所以我最終采用了它。
上面講的第三種方式中動態(tài)加載的
javascript
小工具除了需要生成
UI
供用戶填寫信息(
URL
,
tag
,
notes
等),當(dāng)用戶點(diǎn)擊提交的時(shí)候,還要完成與服務(wù)器通信的功能。在沒有跨域訪問經(jīng)驗(yàn)的情況下,最先想到的當(dāng)然是
ajax
!但很快就會發(fā)現(xiàn)根本行不通。
跨域訪問,簡單來說就是
A
網(wǎng)站的
javascript
代碼試圖訪問
B
網(wǎng)站,包括提交內(nèi)容和獲取內(nèi)容。由于安全原因,跨域訪問是被各大瀏覽器所默認(rèn)禁止的。寫過跨域訪問
ajax
的朋友相信都遇到過被告知“沒有權(quán)限”的情況。通過
XMLHttp
來發(fā)送數(shù)據(jù)給
Bookmark
服務(wù)器的嘗試失敗了。于是,看到網(wǎng)上的一些資料,我又開始嘗試用
javascript
小工具在用戶網(wǎng)頁動態(tài)創(chuàng)建一個(gè)隱藏的
iframe, iframe
的
src
指向服務(wù)器的一個(gè)
servlet
,試圖通過調(diào)用
iframe
中提供的
javascript
來完成與服務(wù)器的通信。但不幸的是,用戶網(wǎng)頁中的
javascript
代碼訪問
iframe
也被瀏覽器歸為跨域訪問(特指
iframe
的
src
指向其它網(wǎng)站的情形),嘗試再次失敗。
最終,在一篇文章中看到,與
iframe
不同,如果
A
網(wǎng)站從
B
網(wǎng)站加載
javascript
,
A
網(wǎng)站可以自由的訪問該
javascript
的內(nèi)容,并不會被瀏覽器認(rèn)為是跨域訪問。模仿剛才
iframe
的思路,當(dāng)用戶點(diǎn)擊提交時(shí),可以動態(tài)創(chuàng)建一個(gè)
javascript
對象,該對象的
src
指向
Bookmark
服務(wù)器的一個(gè)
servlet
,注意:
URL
、
Tag
、
Notes
、
User
、
Password
等信息被作為
src URL
參數(shù)傳給服務(wù)器。請看下面的代碼:
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
參數(shù)提交給了
Bookmark servlet
。那么用戶又如何取得服務(wù)器的響應(yīng)信息呢?答案就是最末一行代碼,
servlet
的輸出必須是
javascript
代碼,它可以調(diào)用用戶網(wǎng)頁上的其他
javascript
函數(shù),以及操作
dom
對象。下面的
servlet
代碼生成了一個(gè)
javascript
函數(shù)調(diào)用:
out.write("onServerResponse(INADEQUATE_INFORMATION);");
document.body.appendChild(js_obj)
執(zhí)行后
onServerResponse(
INADEQUATE_INFORMATION)
就會得到執(zhí)行,使客戶網(wǎng)頁響應(yīng)服務(wù)器結(jié)果。這樣一個(gè)完整的通信過程就完成了。
來總結(jié)一下這個(gè)案例,首先與很多跨域訪問的情形不同,本文提到的跨域訪問需要對服務(wù)器端進(jìn)行控制,即讓服務(wù)器端
Servlet
來適應(yīng)客戶端網(wǎng)頁
javascript
的需求;而其他一些常見的例子則對服務(wù)器端沒有控制能力,比如從其他網(wǎng)站抓內(nèi)容的小偷程序。另外,需要注意的是這種方法中實(shí)際用到了
get
方法來提交信息,從一些資料上看到,
get
方法每次提交的信息不能超過
2k
。
posted on 2006-12-05 22:48 weidagang2046 閱讀(9284) 評論(11) 編輯 收藏