什麼是 JSONP
瀏覽器的同源政策讓我們沒辦法輕易地使用非同源的 response,但是其實 有些元素是不受這個限制的。想想我們可以很自由的嵌入外界的圖片、 library 或者字體嗎?像是 <img>
, <script>
, <img>
(原因可能這些東西本來就很常存取外部資源?),所以我們就可以利用這些 tag 來繞過瀏覽器的 CORS 接收非同源的 reponse。那要怎麼做呢?
怎麼用 JSONP
如果 index.html
裡面有這麼一段程式碼,那會跑出什麼東西?
// index.html
<script>
console.log({name: 'John', age: 14, birth: 1993});
</script>
當然就是在 console 裡面 print 出 {name: 'John', age: 14, birth: 1993}
這段內容,非常之直覺又簡單。那如果是這樣呢?
// index.html
<script src="cross-origin.com/jsonp.js">
// cross-origin.com/jsonp.js
console.log(`{name: 'John', age: 14, birth: 1993}`);
我們在 index.html 中引入 cross-origin.com
中的 jsonp.js
,引入之後會執行 console.log({name: 'John', age: 14, birth: 1993});
。所以做的事情其實和上一段基本上是一樣的。唯一不一樣的是,我們 print 出來的內容是從另外一個網域拿到的,而且 console.log()
這個指令也是在引入的 jsonp.js
所呼叫的。
好,這樣就有點 JSONP 的味道出現了。接下來是重頭戲,下面這樣的程式碼會做甚麼事情?
// index.html
<script>
function print(content) {
console.log(content)
}
</script>
<script src="cross-origin.com/jsonp.js">
// cross-origin.com/jsonp.js
print(`{name: 'John', age: 14, birth: 1993}`);
一樣是 print 出 {name: 'John', age: 14, birth: 1993}
沒錯。但是 jsonp.js 裡面所呼叫的 print 指令卻是是我們自己定義的 function。這個基本上就是 JSONP 運作的方式了,做了兩件事情:
- 透過
<script>
引入外部 Server (另一個網域) 的程式碼 - 外部 Server 的程式碼中執行本地的處理資料的 function,但在 function 中放入外部的資料。
JSONP 就是利用這樣的方式繞過瀏覽器的同源政策,不過我們也發現,整個 JSONP 的精髓都在那個引入的 js 檔案裏面的,要放入我們需要的資料,還需要執行我們本地的 function。
所以重點就變成:外部的 Server 要怎麼去產生執行的 function?也就是我們剛剛的:
// cross-origin.com/jsonp.js
print(`{name: 'John', age: 14, birth: 1993}`);
這點我們通常透過 url 來解決,可能是在後面放上本地中處理資料 function 的名子,像是這樣:
src="cross-origin.com/?jsonp=callback
當 url 設定成這樣,Server 就可以動態產生 js 檔案(也就是依照你的 url 後面的參數去量身訂做一個屬於你的 js 檔案,這對後端來說輕而易舉)。
JSONP 小舉例
最後,在舉個例子,我們看看 Twitch API ,除了使用 AJAX,要怎麼用 JSONP 來獲取資料:
All API endpoints support JSONP by providing a callback parameter with the request:
恩,就在 url 的後面加上 callback=foo
, foo
就帶入自己處理資料的 function 名稱。 url 寫好之後在放入 <sciprt src=url>
tag 中就行。
話說,一開始看 docs 上面, web API 都會寫 curl ,都不知道那是啥,一點也不像 JS,不過後來才知道那只是用 curl 來做 request 的範例而已...
Big Guy is John,感謝大家。