Node.js 和在網頁上呼叫 API 的根本差異
透過 node.js 可以直接呼叫 API,在網頁上是透過瀏覽器,瀏覽器會有一些自己的限制,或是會添加額外的資訊。
傳資料的方式
Form 表單
<form method="POST" action="https://google.com">
username: <input name="username">
<input type="submit">
</form>
伺服器回傳什麼 response 都會被瀏覽器跳頁直接渲染出來
透過 JS 交換資料: AJAX
XMLHttpRequest
const request = new XMLHttpRequest()
//非同步接受響應
//load 是加載完成時觸發
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
console.log(request.responseText)
} else {
console.log("err")
}
}
//error 是加載失敗時觸發
request.onerror = function() {
console.log("error")
}
//3個參數
//傳送的請求的型別、請求的URL、是否非同步傳送請求的布林值
request.open("GET", "http://google.com", true)
//send()方法接收一個引數,即要作為請求主體傳送的資料
//呼叫send()方法後,請求被分派到伺服器
request.send()
--------------------------------------------------
// 上面 request.onload = function(){} 的寫法也可改寫成如下
request.addEventListener("load", function() {
if (request.status >= 200 && request.status < 400) {
console.log(request.responseText)
} else {
console.log("err")
}
})
傳送請求
open()
request.open("GET", "http://google.com", true)
傳送的請求的型別、請求的 URL、是否非同步傳送請求的布林值
send()
呼叫 send()
方法後,請求被分派到伺服器
接收響應
收到響應後,響應資料會自動填充 XHR 物件的屬性,有以下4個屬性:
- responseText: 作為響應主體被返回的文字
- responseXML: 如果響應的內容型別是
text/xml
或application/xml
,這個屬性中將儲存著響應資料的 XML DOM 文件 - status: 響應的 HTTP 狀態
- statusText: HTTP狀態的說明
收到響應後,第一步是檢查 status 屬性,以確定響應已經成功返回,狀態碼為 200 為成功。此時, responseText
的內容就緒,而且在內容型別正確的情況下,responseXML
也可以訪問了
此外,狀態碼為 304 表示請求的資源並沒有被修改,可直接使用瀏覽器中快取版本;當然,也意味著響應是有效的
無論內容型別是什麼,響應主體的內容都會儲存到 responseText
中,而對於非 XML 資料而言,responseXML
將為 null
非同步
如果要接收的是非同步響應,就需檢測 XHR 物件的 readyState
屬性,該屬性表示請求/響應過程的當前活動階段。這個屬性可取的值如下:
- 0 (UNSENT): 未初始化。尚未呼叫
open()
方法 - 1( OPENED): 啟動。已經呼叫
open()
方法,但尚未呼叫send()
方法 - 2 (HEADERS_RECEIVED): 傳送。己經呼叫
send()
方法,且接收到頭資訊 - 3 (LOADING): 接收。已經接收到部分響應主體資訊
- 4 (DONE): 完成。已經接收到全部響應資料,而且已經可以在客戶端使用了
只要 readyState
屬性值由一個值變成另一個值,都會觸發一次 readystatechange
事件。可利用這個事件來檢測每次狀態變化後 readyState
的值。通常,我們對 readyState
值為 4 的階段感興趣,因為這時所有資料都已就緒
[注意] 必須在呼叫 open()
之前指定 onreadystatechange
事件處理程式才能確保跨瀏覽器相容性,否則將無法接收 readyState
屬性為0和1的情況
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status == 200){
alert(xhr.responseText);
}
}
}
XMLHttpRequest 串接 Twitch API 範例
// 注意 callback function 的用法
const APIUrl = 'https://api.twitch.tv/kraken';
const accept = 'application/vnd.twitchtv.v5+json';
const clientId = 'abcde';
function getTopGames(cb) {
const xhr = new XMLHttpRequest();
xhr.open('GET', `${APIUrl}/games/top?limit=5`, true);
xhr.setRequestHeader('Accept', accept);
xhr.setRequestHeader('Client-ID', clientId);
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 400) {
cb(JSON.parse(xhr.response));
}
};
xhr.onerror = () => {
console.log('error');
};
xhr.send();
}
Same origin policy 與跨網域問題
- 同源政策:相同協定且相同網域下才是同源
- 跨來源資源共用 (CORS)
server 的 header 加上 Access-Control-Allow-Origin 才可以拿到 response
Ajax 一定受同源政策的管理
JSONP
有些標籤不受同源政策影響,例如 <img>
和 <script>
一些情況下,可利用 <script>
不受同源政策的限制,跨域存取 Server 的 JavaScript 資料。
單向傳送資料
以 Email 追蹤為例,放一個很小的圖片在 Email 裡面,Client 一打開信的時候就會發送 request 給 Server,Server 就可以知道有沒有打開