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 可以動態加入元件, 這讓使用 style tag 的作法有更多彈性, 可以動態載入其它 domain 的 javascript, 執行裡面的內容, 也方便控制執行的順序。若對方的 javascript 知道自己目前的內容 (DOM、javascript), 就可以搭起兩個網域的資料。於是有了 JSONP 的想法: OTHER-DOMAIN 提供一個 URL, 這個 URL 接受一個參數 callback, 表示 OUR-DOMAIN 寫好的函式名稱。OTHER-DOMAIN 則傳回 CALLBACK({...}) 的程式碼, 用 style 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 的執行方式, 可以省掉自己產生 style tag 執行, 再砍掉它的步驟。
沒有留言:
張貼留言