iT邦幫忙

0

[穩扎穩打系列] AJAX 請求大補帖 - Axios 使用方法、封裝

  • 分享至 

  • xImage
  •  

前言

上篇提到 Axios 是 Clinet 與 Server 溝通的方法之一。
這篇會提到 Axios 是什麼如何安裝使用起手式、以及 Axios 特色方法 攔截器、封裝等。
話不多說,跟著我的腳步,我們一起走吧!!

了解他一下

Axios is a promise-based HTTP Client for node.js and the browser. It is isomorphic (= it can run in the browser and nodejs with the same codebase). On the server-side it uses the native node.js http module, while on the client (browser) it uses XMLHttpRequests. - 取自 Axios 官網

翻譯一下大概就是:

Axios 是由 Promise 的 Http 庫組成的套件。
當使用在客戶端(Client)時,是採取 XMLHttpRequests 的原生庫來進行封裝。
當使用在伺服器端(Server)時,則是採取 Http Module 來進行封裝。

我想上面的部分有點繞口,所以以下這幾點則是我的翻譯以及一些使用前須知,建議先閱讀之後在進行使用。

  1. Axios 實體是透過封裝 XMLHttpRequestHttpModule 來進行實作,這些方式都是一些原生的類別,所以您可以理解成在兼容性不會有其他阿咂的問題。
  2. Axios 是 Ajax 其中一個方式,在流程不外乎就是 包裝請求(建立 Request)-> 伺服器回傳相應資訊(回傳 Response); 所以在建立 Request 的過程中需要進行相應的設定來告知 Axios 該怎麼組成請求,
    並針對請求回傳 Promise,在使用上可以透過 then/catch/finally 來獲取請求完成狀態,相較 XMLHttpRequest 在使用上來的更加精簡,當然因為是 Promise 物件所以可以透過 async/await 進行同步等待。
  3. 相較於 JQuery Ajax 方法,來說瘦的太多太多了,因為 Axios 套件僅僅只有大約 13kb !!

如何安裝

專案中安裝 axios 函式包

在專案中,使用方式有兩種:

  • CDN
  • 載入套件包
套件包
npm install axios
yarn add axios
CDN
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">

使用起手式

基本使用方式 axios(config)

在使用之前我們先來了解一下 Request 的 config,下面會挑選幾個常用的設定進行介紹。

axios({
  //- `url`: 相對/絕對路徑,當 baseURL 並未進行設定時,需為絕對路徑。
  url: "/call/me", 
  //- `method`: 請求方法最常聯想到的是 RESTful API : GET POST PUT PUTCH DELETE
  method: "get", 
  //- `baseURL`: 設定 API 所屬網域
  baseURL: 'https://thisCanGiveMeDataWebAPIURL.com', 
  //- `headers`: Request Header 設定最常設定內容有 APIToken
  headers: {'X-Requested-With': 'XMLHttpRequest'}, 
  //- `params`: 會隨請求一起發送的 URL 參數,當 Method 為 GET 時會當作是 payload 一同送出。
  params: {
    ID: 12345
  },
  //- `data`: 為 body 實體送出,僅能使用於'PUT'、'POST'、'DELETE 和 'PATCH'
  data: {
    firstName: 'Fred' 
  },
  //- `timeout`: 當設定毫秒數到時會自動取需 API 溝通。
  timeout: 1000, 
  //- `withCredentials`: 表示是否跨站訪問控制請求
  withCredentials: false, 
  //- `auth`: 此參數為了是與後端透過 Authorization header 進行溝通時需要進行設定,如果您的需求是 Bearer tokens 時則需直接在 header 裡面建立 {Authorization: `Bearer ${token}`}
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },
  //- `responseType`: response 回覆格式
  responseType: 'json',
  //- `responseEncoding`: response 回覆編碼
  responseEncoding: 'utf8',
  //- `cancelToken`: 用於取消請求
  cancelToken: new CancelToken(function (cancel) {}), 
  
  ...
})

在發送請求後,當然會有一個回傳的資料摟~而這邊的回傳資料。
下列幾個是一定要知道的 Reaponse 類別。

{
  // `data`: Server 回應 Data 實體
  data: {},

  // `status`: Server 回應此請求 Http Status Code
  status: 200,

  //  `statusText`: Server 回應此請求 Http Status Code message
  statusText: 'OK',

  // `headers`: Server 回應此請求的 header
  headers: {},
  
  ...
}

在了解上面的基本設定之後我們來開始使用他吧!但只是單純空講我相信還是會很不清楚包含我自己,所以我們這邊的例子就依照 台中市政府資料公開平台臺中市領有溫泉標章之溫泉來進行實作吧!!

E.G. GET

axios({
    method: 'get',
    baseURL: 'https://datacenter.taichung.gov.tw/Swagger',
    url:'/OpenData/678b53a2-6de4-4052-90b4-0847eb1d7a5b',
    params: {}
  })
    .then(res=>{
      console.log(res)
    })
    .catch(err=>{
      console.log(err)
    })

可以看到這邊將 res 直接進行 console.log 出來的結果會是
GET 嘗試搓 open api

是不是更上面所說的 Reaponse 物件一樣呢,所以聰明的你應該已經想到該怎麼透過物件來取的資料了對吧!
沒錯就是透過 res.data 來獲取資料內容!!

附上進行資料處理的過程

axios({
    method: 'get',
    baseURL: 'https://datacenter.taichung.gov.tw/Swagger',
    url:'/OpenData/678b53a2-6de4-4052-90b4-0847eb1d7a5b',
    params: {}
})
.then(res=>{
  const data = res.data.reduce((obj,datum) => {
    if(!(datum.溫泉地區 in obj)) obj[datum.溫泉地區] = []
    obj[datum.溫泉地區].push({name:datum.經營名稱, place: datum.溫泉地區})

    return obj
  },{})

  let str = ''
  Object.entries(data).forEach(([key,value])=>  str+=`<h3>${key}</h3><ul>${value.map(node=>`<li>${node.name}</li>`).join('')}</ul>`)
  document.getElementById('tag').innerHTML = Object.keys(data)
  document.getElementById('wrap').innerHTML = str
})
.catch(err=>{
  console.log(err)
})

這樣就可以條列式的看見領有溫泉標章之溫泉的廠商摟 Demo

E.G. POST

axios({
   url: 'blog/new',
   method: "POST",
   baseURL: 'https://yourDomin.com/',
   data:{
    account: 'test111',
    body:'<h1>測試</h1>'
   }
})
    .then( (response) => console.log(response))
    .catch( (error) => console.log(error))

特色講解(封裝、攔截器)

封裝

我相信工程師都是偷懶的,人因偷懶而進步,於是我們來學習怎麼偷懶吧(誤)!
相信大家在使用 Axios 時都會感覺到厭煩,因為在每次的發送之前都需要進行一大堆的設定 config,像是 baseURL 反覆設定。

axios({
    method: 'get',
    baseURL: 'https://datacenter.taichung.gov.tw/Swagger',
    url:'/OpenData/678b53a2-6de4-4052-90b4-0847eb1d7a5b',
    params: {}
})

又或者當需要 token 時總是會反覆寫相同的判斷。

const config = {
    method: 'get',
    baseURL: 'https://datacenter.taichung.gov.tw/Swagger',
    url:'/OpenData/678b53a2-6de4-4052-90b4-0847eb1d7a5b',
    params: {}
}

if(needToken) config.header.apiToken = token

axios(config)

於是乎我們來學會封裝吧。
先來定義我們想要怎麼呼叫來降低重複 codeing。
我希望在使用的時候建立 xhr.js,透過 import 的方式將封裝後的 axios 引用至需要 js 檔案之中,並且呼叫 xhr(config) 來建立 axios 請求。

//- 預期使用方式
//- needToken 判斷是否需要 token 
xhr({
  needToken,
  url,
  method,
  params,
  data,
})
//- xhr.js

const xhr = ({url,data,params,method,needToken}) => {
    //- 建立相同設置,這裡可以做很多很多事情,例子中是透過 needToken 來控制是否需要 token
    const _axios = axios.create({
      baseURL: 'https://datacenter.taichung.gov.tw/Swagger',
      headers: { 'Content-Type': 'application/json' },
      timeout: 20000
    });

    return new Promise((resolve,reject)=>{
      const config = {url,data,params,method}

      if(needToken) config.headers.token = token

      _axios(config)
        .then((res)=> resolve(res.data))
        .catch((err)=>reject(err))
    })
  }


export default xhr

//- 外部引用方式

xhr({
    url:'/OpenData/678b53a2-6de4-4052-90b4-0847eb1d7a5b',
    method: 'get',
    needToken: false,
})
.then(res=>res)
.catch(err=>err)

多了一層的 xhr 來進行封裝 axios 可以針對特殊處理像是 1. token 判斷 2. 針對回傳進行特定處理 3. token 失效進行什麼判斷... 等,有很多的應用可以在這一層進行處理。

攔截器

其實針對上方寫法, Axios 其實有提供 Interceptor(攔截器),來擷取發送 request 之前、獲取 response 之後,可以進行相應的設定,通常用於所有 request / response,相同的資料處理,詳情可以看下面這張圖片。

https://ithelp.ithome.com.tw/upload/images/20230306/20155307UpeKQkinnI.png

所以我們可以改寫上方的 xhr.js ,就更加精簡摟。

設定 axios interceptor

const xhr = () => {
    const _axios = axios.create({
      baseURL: 'https://datacenter.taichung.gov.tw/Swagger',
      headers: { 'Content-Type': 'application/json' },
      timeout: 20000
    });

    // 攔截 Request
    _axios.interceptors.request.use((req)=>{
      //- 這裡要特別註記
      if(needToken) req.headers.token = 'rereqwrwevmlpodsjvopsdkv'
      //- 針對 config 進行配置
      return req
    },err=> {
      //- 當請求發送失敗時,此狀況在於無法發送的狀態
      return Promise.reject(err);
    })

    // 攔截 response
    _axios.interceptors.response.use((res)=>{
      //- 針對回傳進行相應處理,可能是擷取部分資訊。
      return res.data
    },err => {
      //- 當伺服器端回應失敗,
      return Promise.reject(err)
    })
    
    returm _axios
}

export default xhr

//- 外部引用方式

xhr({
    url:'/OpenData/678b53a2-6de4-4052-90b4-0847eb1d7a5b',
    method: 'get',
    needToken: false,
})
.then(res=>res)
.catch(err=>err)

如何是不是變的簡單明瞭,好維護了呢,大致上就是這些摟!!

謝謝各位觀看!!

引用

Axios GitHub
[Axios] (https://axios-http.com/docs/intro)

資料來源

台中市政府資料公開平台-臺中市領有溫泉標章之溫泉


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言