# [JavaScript] Fetch ###### tags: `前端筆記` ## 使用原生的方法來接收 API 資料吧 為了達到 AJAX(Asynchronous JavaScript And XML、非同步 JavaScript 與 XML)的接收資料網頁不換頁的效果,懂得如何接受伺服器的資料很重要。 如果不想要使用很古老的 `XMLHttpRequest`,來接受第三方 API 的話,那就試試看 `Fetch` 吧。 ## `Fetch` 的語法解析 ```javascript= fetch(resource [, optional]) ``` `Fetch` 的使用比 `XMLHttpRequest` 來的簡單,**每次都會回傳 `Promise` 實現非同步執行。** 範例參考自:[Using Fetch](https://developer.mozilla.org/zh-TW/docs/Web/API/Fetch_API/Using_Fetch) ```javascript= fetch('http://example.com/movies.json') .then(function(response) { return response.json(); }) .then(function(myJson) { console.log(myJson); }); // 嘗試從 'http://example.com/movies.json' 取得資料 // 基本上只要一個網址參數就可以收 API 的資料了 ``` 第一個參數(`{String}`)固定是放取得資料的來源(比方來說 API 的網址等),第二個參數(`{Object}`)則是選擇性的,比方來說可以放取得資料來源需要的 `headers` 屬性。 ### 第二個參數常用的屬性 1. `method`:http verbs,沒有特別寫出來的話預設是 `GET` 2. `body`:當使用 `POST` 來給伺服器資料的話就要把資料寫在這邊,**寫給伺服器的資料要記得用 `JSON.stringify` 資料轉成字串的形式,要不然伺服器會沒辦法收** 3. `headers`:發送請求(request)的表頭,通常會寫 `'Content-Type': 'application/json'` 來告訴伺服器說我現在要傳什麼型態的資料給你了。或者 API 需要金鑰認真發送請求的是誰時也要把對應的金鑰 ID 及 KEY 寫在這裡 還有很多[屬性](https://developer.mozilla.org/en-US/docs/Web/API/fetch),這邊先整理我常用的屬性。 ## `Fetch` 要記得再解析後的資料 執行完會得到 `Response` 物件,資料則是會在其 `body` 屬性裡面,但還需要進一步解析(使用 `Response` 的物件其他方法)才可以得到資料。 ```javascript= fetch('https://randomuser.me/api/') .then(response => console.log(response)); ``` ![](https://i.imgur.com/fC8Tmqv.png) 最常用的就是 `json()取得 JSON 再轉 JavaScript` 或者 `text()取得純 HTML`(當然還有其他[方法](https://developer.mozilla.org/zh-TW/docs/Web/API/Fetch_API/Using_Fetch))。**使用解析方法後都會再回傳一個已實現的 `Promise` 物件,所以還需要再使用 `then` 來取得已經解析的資料(物件)。** ```javascript= fetch('https://randomuser.me/api/') .then(response => response.json()) // 被轉成 JSON .then(data => console.log(data)); // 後來被轉成 JavaScript ``` ![](https://i.imgur.com/W4YmtVF.png) ### 注意解析後回傳的是已經「實現的」 `Promise` 可以看到解析回來的 `Promise` 是已經「實現」。 ```javascript= fetch('https://randomuser.me/api/') .then(response => { console.log(response); return console.log(response.json()); }); ``` ![](https://i.imgur.com/IhV3Ese.png) ### 那要怎麼確認是不是 API 那邊出了問題呢? 這個時候就要在「收到資料的時候」檢查(也就是解析以前檢查是不是出了問題)。收到資料的 `Response` 中有 `ok` 及 `status` 這兩個屬性可以得知接受資料的狀態。 - `ok` 會有 `true` / `false` - `status` 如果成功就是 200 - `statusText` 可以看到出錯的原因 ![](https://i.imgur.com/JJcvghg.png) ```javascript= fetch('https://randomuser.me/api/') .then(response => { if (!response.ok) { throw Error('ERROR'); } return response.json(); }) .then(data => console.log(data)) .catch(error => console.log(error)); ``` 當然也可以把處理 error 的函式寫出來。 ```javascript= fetch('https://randomuser.me/api/') // 跟 addEventHandler 一樣 // => 叫用時不需再下 argument // => 但宣告的時候記得要寫 parameter .then(fetchErrorsHandle) .then(data => console.log(data)) .catch(error => console.log(error)); function fetchErrorsHandle (response) { if (!response.ok && response.status !== 200) { throw Error(response.statusText); } return response.json(); } ``` ## 除了收資料,也可以送資料 也可以使用 `fetch` 把資料傳到伺服器中。 `method` 預設就是 `GET`,但 `GET` 沒辦法使用傳送資料時放資料的 `body` 屬性,所以要記得設定 `method: POST`,另外,在 `body` 的 value 前記得使用 `JSON.stringify()` 把 `JSON` 改成字串,要不然伺服器會沒辦法收到正確型態的資料。 ```javascript= fetch('http://httpbin.org/post', setHeaders()) .then(res => { return res.json() }).then(data => console.log(data)); function setHeaders () { const headers = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body : JSON.stringify({ name: 'QQQ' }) }; return headers; } ``` ![](https://i.imgur.com/aFDKG0k.png) 沒寫 `method: POST` ![](https://i.imgur.com/DAmrYQY.png) ## 也可以分割任務 啟動 => 接收 + 解析 => 解析之後才做 ```javascript= const fetchData = (url) => { // 負責啟動 fetch return fetch(url) .then(fetchErrorsHandle); // .then(data => console.log(data)); }; function fetchErrorsHandle (response) { // 檢查錯誤 // 解析 if (!response.ok && response.status !== 200) { throw Error(response.statusText); } // console.log(123132123); return response.json(); } function showResult (url) { // 負責做收到資料要做的事情 // => 收到解析的資料後,才做 // => 所以是非同步,記得寫在 then 裡 fetchData(url).then(data => { console.log(data); }); } showResult('https://randomuser.me/api/'); ``` ## 總結 **`Fetch` 是使用 `Promise` 的模式!所以要用 `then` 來執行實現後的任務。** 以上就是除了 `XMLHttpRequest` 外使用原生的方法接受第三方 API 資料的方式,當然現在還有其他熱門的套件(比方來說 `axios`)等到 `fetch` 稍微上手後再使用套件的幫忙好了。 ## 參考資料 1. [Learn Fetch API In 6 Minutes](https://www.youtube.com/watch?v=cuEtnrL9-H0&t=53s) 2. [JacaScript | Fetch 讓 ES6 擁有一對翅膀-基礎教學](https://medium.com/enjoy-life-enjoy-coding/jacascript-fetch-%E8%AE%93-es6-%E6%93%81%E6%9C%89%E4%B8%80%E5%B0%8D%E7%BF%85%E8%86%80-%E5%9F%BA%E7%A4%8E%E6%95%99%E5%AD%B8-2f98efe55ba4) 3. [Using Fetch](https://developer.mozilla.org/zh-TW/docs/Web/API/Fetch_API/Using_Fetch)