如何用 JavaScript 執行不同網域的 script

因為XSS的安全性問題,所以不能使用XMLHttpRequest的抓不同網域的資料,這限制了部份 mashup 的發展,不過經過測試,加上Ajax Patterns的佐證,發現實際上還是有方法的。

其實方法很簡單,就是用 JavaScript 來新增script標籤,像是支援度最高的document.write法:

document.write("<script type=\"text/javascript\" src=\"http://othree.net/tmp/test.js\"><\/script>");

或是標準的DOM方法(如果使用text/html的mime type就不得不用這種方法了):

var z1 = document.createElement("script");
z1.type = "text/javascript";
z1.src = "http://othree.net/tmp/test.js";
document.getElementsByTagName("head")[0].appendChild(z1);

不過這和抓資料有什麼關係呢?重點在遠端的那個 JavaScript 內容,它可以把需要的資料存到一個變數內,像是:

testvar = "You got me !";

這時問題又來了,一般web service就是直接提供JSON字串或是XML字串,並不會像上面轉成變數,這確實是最大的問題,目前我的解決方法還是需要透過一個自己可以動的server把web service回傳的字串包裝成上面的樣子再傳給網頁,不過這樣速度還蠻慢的,而且也不是每個人都有辦法弄出支援PHP、Perl等server side script的空間,而且要是有作這種東西的話就不會有跨網域的問題了吧,不過這我目前也沒辦法啦><。

還有一個問題,要怎樣抓到遠端script完整執行完的事件呢?這我試驗了很久,目前的作法如下:

<script type="text/javascript">
document.write("<script type=\"text/javascript\" src=\"http://othree.net/tmp/test.js\"><\/script>");
</script>
<script type="text/javascript">
alert(testvar);
</script>

沒錯,你需要兩個script標籤才能確保下面的alert事件會等到遠端script執行完才會動作,這當然是很爛的作法,因為是hard code,而且要把script寫在html原始碼裡面,有違行為、內容樣式分開的原則,加上不能包在function裡面,不過為了IE、Safari兩個瀏覽器的支援,不得不這樣寫......好吧,其實還有個方法,僅限於你能決定web service回傳的檔案內容是什麼時,當然為了解決前一個問題所作的web service proxy也是可以辦得到的,就是把遠端script的內容改成:

testvar = "You got me !";alert(testvar);

就是遠端script的最後自己呼叫該執行的function,恩,還是很不好看,不過至少是我目前找的唯一方法。

補充:根據這兩天的測試,Firefox和Opera在script的執行順序很合直覺,IE在一個script區塊裡面一定會先把本地端的執行完才執行遠端的,Safari則是同時跑兩邊。