2011年3月26日 星期六

Same origin policy 和 JSONP

Wikipedia 上有清楚的範例說明 Same origin policy, 瀏覽器端的 javascript 只能存取 protocol、domain name、port 一致下的檔案。若沒有這個限制的話 [*1], 網站 A 就能透過使用者取用網站 B 的內容, 後果不堪設想。但是, 現今做網站常需要整合其它網站的內容, 像是在自己的網站用 Flickr 的相片, 用 Google Map 的地圖等, 必須要有方式安全地避開 Same origin policy。
備註 1: 我自己測的結果, 用 ajax 連到其它網域要東西, 對方的 server 還是會收到請求, 並傳回 200, 只是 ajax 不會得到結果, 我猜應該是瀏覽器自己擋掉拿回來的結果。所以, 即使有 same origin policy, 還是有可能讓使用者狂連其它網站, 浪費別人的資源。但也會留下 referral log 就是了。
《JavaScript 抓取跨網域外的資 清楚的說明避開 Same origin policy 的兩個作法
  • 透過自己網站的 proxy script, 就沒有 same origin policy 的限制。也就是說, 自己先寫好一個 proxy script (用 PHP / CGI,  什麼都可以), 要取用其它網域的檔案時, 先連到自家的 proxy script, 透過它連向目標 URL, 再直接傳回收到的結果。缺點是會增加 latency, 還有增加自家網站的負擔。
  • html tag 沒有跨網域的限制 (不然連載入其它網站的圖和 CSS 都很麻煩), 可以用 <script type="text/javascript" src="http://OTHER-DOMAIN/some.js"></script> 載入執行另一個網域的 javascript。
由於 HTML 可以動態加入元件, 這讓使用 script tag 的作法有更多彈性, 可以動態載入其它 domain 的 javascript, 執行裡面的內容, 也方便控制執行的順序。若對方的 javascript 知道自己目前的內容 (DOM、javascript), 就可以搭起兩個網域的資料。於是有了 JSONP 的想法: OTHER-DOMAIN 提供一個 URL, 這個 URL 接受一個參數 callback, 表示 OUR-DOMAIN 寫好的函式名稱。OTHER-DOMAIN 則傳回 CALLBACK({...}) 的程式碼, 用 script tag 載入後會自動執行, 結果就是用 OUR-DOMAIN 的 CALLBACK 接受 OTHER-DOMAIN 「傳回」的 JSON 物件 ( 即 {...} ), 達到跨網域的需求。必要時 OTHER-DOMAIN 也可以多產生一些程式碼, 做些 CALLBACK 的前處理和後處理。
Wikipedia 有詳細的 JSONP 例子, 另外這裡這裡也有不錯的例子, 觀察 server side (即 OTHER-DOMAIN) 和 client side (即 OUR-DOMAIN) 的原始碼和中間產生的 code, 就能明白它運作的機制。
使用 JSONP 的代價就是, 使用者得相信提供 JSONP API 的網站不會亂搞, 偷產生惡意程式碼, 這有點像接受外部的輸入, 再執行 eval 一樣, 方便歸方便, 卻有一定的風險。另外 jQuery 有提供 JSONP 的執行方式, 可以省掉自己產生 script tag 執行, 再砍掉它的步驟。

2 則留言:

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...