傳統的XMLHttpRequest
(以下我們簡稱 XHR )
XHR 對於開發者來說相當陌生,大概十年前的人都覺得操作 XHR 很煩,否則怎麼會有 jQuery 的 ajax 誕生呢?
話不多說,來看看最簡單的 XHR 範例(MDN):
function reqListener () {
console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send();
- 創建
XMLHttpRequest
的實例 — oReq - 在
open
設定「請求方法」以及「目標」 - 掛載
load
callback - 使用
send
方法發起請求
請求回來後,依照 load 的回調來決定怎麼處理資料,挺饒舌的。
一樣的事情在 Fetch 該怎麼做呢?
fetch("http://www.example.org/example.txt")
.then(res=>res.text())
.then(console.log)
其實有點作弊,因為 fetch 如果不指定方法的話會使用 GET 。
還可以更作弊嗎?由於是回傳 Promise ,可以用 ES7 的 await 做的更好懂:
let res = await fetch('http://www.example.org/example.txt"');
let text = await res.text();
console.log(text);
先封裝上述例子
const fetches = target =>
new Promise((resolve,reject)=>{
const XHR = new XMLHttpRequest();
XHR.open('GET',target);
XHR.addEventListener('load',()=> resolve(new Response(XHR.response)));
XHR.send();
})
由於 fetch 後的第一個 then 拿到的是 Response實體,使用我們必須在 resolve 內傳入。
Error 處理
我們多加入一個監聽器,來監聽 error 事件是否發生。
XHR.addEventListener('error', reject)
初步的 fetch 就快實現了。
實際上的 fetch
fetch(url, {
body: JSON.stringify(data),
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST',
})
我們可以知道一件事 fetch 接受兩個參數,這邊稱為 args[0]
與 args[1]
好了。
- 目標是 args[0]
- 如果 args[1] 不存在 → GET 請求
- 如果 args[1] 存在,且args[1].method 存在 → 有指定 method
- 如果 args[1] 存在,且args[1].headers 存在 → 存在headers
- 如果 args[1] 存在,且args[1].body 存在 → 存在body
我們就一一塞進去吧!
XHR 怎麼設定 Headers?
XHR.setRequestHeader(key, value)
假設 args[1].headers
存在,我們也要用一樣的方式,把該 object 的 key 與對應的 value 塞進去。
依照上述邏輯封裝後的 Fetch
首先我們把 args 裡頭的資訊,包括目標 URL、method、Headers、body,抽取出來,並且丟進我們設計好的 Promise XHR。
第五行所做的事就是依照 Header 物件的 Key 遍尋所有對應的 value,並且依照 setRequestHeader
塞進去。
大功告成。
來試試看 fetches 吧
我們來透過開放跨域請求的https://httpbin.org/ 來測試吧!由於 Medium 有設定 CSP (Content Security Policy) ,所以可以的話其他分頁試試看吧!
不提供 args[1] 的 fetch
fetches('https://httpbin.org/get')
.then(res=>res.text())
.then(console.log)
提供 args[1] 的 GET (with headers)
fetches('https://httpbin.org/get',{
method:'GET',
headers: {
'author': '@realdennis'
}
})
.then(res=>res.text())
.then(console.log)
POST (with body)
fetches('https://httpbin.org/post',{
method:'POST',
body:JSON.stringify({whoami:'realdennis'}),
})
.then(res=>res.text())
.then(console.log)