iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 28
2
Modern Web

JavaScript基本功修煉系列 第 28

JavaScript基本功修練:Day28 - Fetch練習(GET和POST請求)

今天會承接昨天AJAX的課題,了解常用來處理AJAX的語法,Fetch,以及試試用fetch來實作GET、POST請求。

fetch基本語法

Fetch是一個全域window物件,用途是送出request。當請求成功,fetch就會回傳一個promise物件(狀態是fulfilled),這物件內會帶有response物件,裏面會放有我們想抓的資料。

fetch語法:

let promise = fetch(url, [options])
  • url是要訪問的網址
  • options是一堆可選的参數,例如method、header

如果只有url,沒有[options],就會預設這個請求的HTTP請求方法是GET。

Fetch的語法結構與Promise非常相似,同樣是用thencatch方法來處理成功和失敗的結果:

fetch( 你想訪問的url,{...一堆参數(可選)} )
    .then((response) => {
        //成功結果處理
    })
    .catch((error) => {
        //錯誤結果處理
    })

當透過fetch語法,從瀏覽器向伺服器發出GET請求後,接下來的流程可分為兩大部分。以下會用https://randomuser.me/api/去做一個簡單示範,這個API會隨機產生一個人的資料。

階段1: fetch傳回帶有Response物件的Promise物件

fetch('https://randomuser.me/api/')
    .then((response) => {
        console.log(response); 
    })
    .catch((error) => {
        console.log(`Error: ${error}`);
    })

我們可以從statusok查看HTTP狀態。ok是一個布林值,如果status是200-299,它就是true

階段2: 從Response物件中抽取我們想抓的資料

雖然在階段一回傳了Response物件,但這不是我們想抓的資料,即是我們常常說的「回應內容主體(Response body)」,接下來我們需要使用方法來取得它。

Response有多種方法讓我們取得資料(內容主體),包括我們常常用到的.json()

  • response.json():把資料轉成JSON格式
  • response.text():把資料轉成text格式(變成純字串)
  • response.blob():把資料轉成Blob物件
  • response.formData():把資料轉成FormData物件
  • response.arrayBuffer():把資料轉成二進制數組

注意,只能使用一種方法來取得資料。例如我用了.json()的方法後,不能再用另一種方法來取得資料,因為該資料已經被處理過了。

我們最常用到就是JSON格式資料,以下例子會用.json()的方法取得資料:

fetch('https://randomuser.me/api/')
    .then((response) => {
        return response.json();
    })
    .then( (response) => {
        console.log(response);
    })
    .catch((error) => {
        console.log(`Error: ${error}`);
    })

最後就取得資料了:

async/await的寫法原理是一樣的,以下試試用async/await去重寫以上例子:

let getJSON = async(url) => {
    let response = await fetch(url);
    let JSON = await response.json();
    console.log(JSON)
}

getJSON('https://randomuser.me/api/')

Header

上面曾提及過,在fetch()裏可以有兩個参數,第一個是URL,第二個是一堆参數,例如methodheader等等。當中的header就是Request header,即是請求表頭,它用來描述我們發出的請求,例如是請求URL、請求方法。

Header這個術語是指表頭,可以分為請求表頭(Request header)與回應表頭(Response header),它們是一堆描述這個請求或回應的資訊。我們可以用dev tool看到這些資訊:

請求表頭及回應表頭的格式是有規範,否則不能被伺服器或瀏覽器接收。以下例子示範自訂一個請求表頭:

let response = fetch('https://randomuser.me/api/',{
    headers: {
        Authentication: 'secret'
    }
});

但基於HTTP的準確與安全性,某些設定是不能被我們定義,只能被瀏覽器定義。

POST

當我們發出POST請求時,就需要用到fetch裏的第二個参數,當中包括:

  • method (HTTP請求方法)
  • request body (請求主體)

當中的request body,例如可以是:

  • 字串(用JSON.stringify轉成的字串)
  • FormData物件
  • Blob所傳送的二進制資料

以下用六角學院的API作例子,註冊後會得到一個獨立編碼(UUID),這個UUID是用來組成自己的API網址時用的,另外也會提供一個API token(後台登入驗證碼),用來驗證是否有管理員身分,並能夠管理個人專屬的後台。

這裏會示範如果新增一筆產品資料到伺服器,剛才提及uuid和token是在註冊六角學院的API系統時發給我的,我把它們放在一個個的變數裏,但這裏就不公開了。

新增一筆產品資料的API文件:

Body Parameters就是主體参數,要寫在fetch(url,{...}){...}裏。

以下是完整程式碼:

const uuid = xxxxx
const token = xxxxx
const url = `https://course-ec-api.hexschool.io/api/${uuid}/admin/ec/product`

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "Authorization": `Bearer ${token}`,
}

//以下是API文件中提及必寫的主體参數。而以下這個產品資料是六角學院提供的。
let body = {
    "title": "Abysswalker",
    "category": "T-Shirts",
    "content": "Its wearer, like Artorias himself, can traverse the Abyss.",
    "description": "This official Dark Souls shirt was designed by Nina Matsumoto and printed on soft 100% cotton shirts by Forward. Each one comes with a bonus sticker.",
    "imageUrl": ["https://images.unsplash.com/photo-1529374255404-311a2a4f1fd9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1349&q=80"]
}

fetch(url, {
    method: "POST",
    headers: headers,
    //別忘了把主體参數轉成字串,否則資料會變成[object Object],它無法被成功儲存在後台
    body: JSON.stringify(body)
})
    .then(response => response.json())
    .then(json => console.log(json));

結果:

如果我新增了3次這筆資料,後台就會有3筆資料,我們也可以用"GET"的方法去查詢,六角學院提供了以下的API文件:

完整程式碼:

const url = `https://course-ec-api.hexschool.io/api/${uuid}/admin/ec/products`

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "Authorization": `Bearer ${token}`,
}

fetch(url, {
    method: "GET",
    headers: headers,
})
    .then( (response) => response.json())
    .then( (json) => console.log(json));

結果真的會顯示3筆資料:

總結

雖然之前已經學了Promise語法,學習Fetch時不會太吃力,但認真落手實作時才發覺也有一定的難度,而且當中有些術語,例如Body parametres、Header等等也沒有看懂,所以除了看文章,也真的是需要實作練習一下~

参考資料

AJAX 完整解說系列:新增、更新、刪除(POST、PATCH、DELETE)
JAVASCRIPT.INFO
JacaScript | Fetch 讓 ES6 擁有一對翅膀-基礎教學
鐵人賽:ES6 原生 Fetch 遠端資料方法


上一篇
JavaScript基本功修練:Day27 - AJAX基本概念
下一篇
JavaScript基本功修練:Day29 - axios基本語法與練習(GET、POST請求)
系列文
JavaScript基本功修煉31

尚未有邦友留言

立即登入留言