Elaine's Blog 朝著 senior 前進的工程師

axios

2019-10-31

安裝 axios

  • npm

      $ npm install --save axios
    
  • cdn

      <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    

使用方式

axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

axios 特點

  1. 基本 Promise 的異步 AJAX 請求庫 (封裝 XHR)
  2. 瀏覽器端與 NodeJS 端都可以使用
  3. 支援 Request 與 Response 的攔截
  4. 支援取消 Request
  5. Request 與 Response 的資料轉換 (轉為 JSON)
  6. 批量發送多個 Request

axios 常用語法

  • axios(config)
  • axios(url[, config])
    • 指定用 GET 發送 Request
  • axios.request(config)
    • 等同於 axios(config)
  • axios.get(url[, config])
  • axios.post(url[, config])
  • axios.put(url[, config])
  • axios.delete(url[, config])
  • axios.defaults.xxx
    • 全域配置
  • axios.interceptors.request.use()
  • axios.interceptors.response.use()
  • axios.create([config])
  • axios.Cancel()
    • 取消 Request
  • axios.CancelToken()
    • 取消 Request 的 Token 物件
  • axios.isCancel()
    • 是否為一個取消 Request 的錯誤
  • axios.all(promises)
    • 用來批量執行多個異步 Request
  • axios.spread()
    • 用來指定接收所有成功資料的 callback

config

const config = {
	url: "/users", // 必填
	method: "post", // 大小寫皆可,預設是 get
	headers: { "Content-Type": "application/json" },
	baseURL: "http://localhost:3000", // 會自動加在 url 前面,除非 url 為絕對路徑
	timeout: 1000,
	data: { name: "test", title: 777 },
	params: { ID: 123 },

	// paramsSerializer 是一个負責 params 序列化的函数
	// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
	paramsSerializer: function(params) {
		return Qs.stringify(params, { arrayFormat: "brackets" });
	},

	// transformRequest 允許在發請求前,修改 Request 資料
	// 只能用在 'PUT', 'POST' 和 'PATCH'
	// 後面陣列中的函數必须回傳一个字符或 ArrayBuffer 或 Stream
	transformRequest: [
		function(data) {
			// 對 data 進行任意轉換
			return data;
		},
	],

	// transformResponse 在傳给 then/catch 前,可以修改 response 資料
	transformResponse: [
		function(data) {
			// 對 data 進行任意轉換
			return data;
		},
	],

	// 伺服器回應的數據類型
	// 選項: 'arraybuffer', 'document', 'json', 'text', 'stream'
	// 瀏覽器才有 'blob',預設為 'json'
	responseType: "json",

	// 伺服器回應的編碼模式 預設 'utf8'
	responseEncoding: "utf8",

	// 限制 Response 大小
	maxContentLength: 2000,

	// 在上傳、下載途中可執行的事情 (progressBar、Loading)
	onUploadProgress(progressEvt) {
		/* 原生 ProgressEvent */
	},
	onDownloadProgress(progressEvt) {
		/* 原生 ProgressEvent */
	},

	// xsrfCookieName 是用作 xsrf token 的值的 cookie 的名稱
	xsrfCookieName: "XSRF-TOKEN", // default

	// xsrfHeaderName 是乘載 xsrf token 的值的 HTTP Header 的名稱
	xsrfHeaderName: "X-XSRF-TOKEN", // default

	// 允許自定義處理請求,可讓測試更容易
	// return promise 並提供有效的回應 (valid response)
	adapter(config) {},

	// 表示跨域請求時是否需要使用 cookie,預設是 false
	withCredentials: false,

	// 必須提供 credentials (Cookie)
	// 等同 Authorization 表頭
	// 如果使用 token 應去 header 設置 Authorization 而非使用此
	auth: { username: "Mark", password: 123 },

	// 用來判斷是否解析 Promise 的 狀態碼範圍
	validateStatus: function(status) {
		return status >= 200 && status < 300; // default
	},

	maxRedirects: 5, // 預設為 5 次

	// xsrf token 的 Cookie名 / Header名
	xsrfCookieName: "XSRF-TOKEN", // default
	xsrfHeaderName: "X-XSRF-TOKEN", // default

	// 代理伺服器
	proxy: {
		host: "127.0.0.1",
		port: 9000,
		auth: {
			username: "mikeymike",
			password: "rapunz3l",
		},
	},

	// 用來取消請求的 token
	cancelToken: new CancelToken(function(cancel) {}),
};

回傳

{
	data: {},
	status: 200,
	statusText: "OK",
	headers: {},
	config: {}, // Request 的 config
};
axios.get('/user/12345')
  .then(function(response) {
    console.log(response.data);
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.headers);
    console.log(response.config);
  });

axios.create()

  1. 創建一個實例

     const instance = axios.create({
       baseURL: 'https://some-domain.com/api/',
       timeout: 1000,
       headers: {'X-Custom-Header': 'foobar'}
     });
    	
     // 程式的某個地方再修改為
     instance.defaults.baseURL = 'https://other-domain.com/api/';
    
  2. 使用實例的方法

     instance.get('/longRequest', {
       timeout: 5000
     });
    

攔截器

  • 新增攔截器

      // 新增請求攔截器
      axios.interceptors.request.use(function (config) {
          // 在發請求前做一些事
          return config;
        }, function (error) {
          // 對失敗的請求做一些事
          return Promise.reject(error);
        });
    
      // 新增回應攔截器
      axios.interceptors.response.use(function (response) {
          // 對回傳值做一些事
          return response;
        }, function (error) {
          // 對失敗的回應做一些事
          return Promise.reject(error);
        });
    
  • 新增實例的攔截器

      var instance = axios.create();
      instance.interceptors.request.use(function () {/*...*/});
    
  • 移除攔截器

      var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
      axios.interceptors.request.eject(myInterceptor);
    

取消請求

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 處理錯誤
  }
});

// 取消請求(message 參數可選)
source.cancel('Operation canceled by the user.');

併發請求 axios.all

  • 類似 Promise All 用法
  • then 後接 axios.spread
function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 兩個請求都完成
  }));

模擬實作一個簡易版的 axios

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>模擬 axios</title>
    </head>
    <body>
        <button onclick="testGet()">get</button>
        <button onclick="testPost()">post</button>
        <button onclick="testPut()">put</button>
        <button onclick="testDelete()">delete</button>
        <script>
            function axios({ url, method = "GET", params = {}, data = {} }) {
                method = method || "GET";
                method = method.toUpperCase();

                let query = [];
                Object.keys(params).forEach((key) => {
                    query.push(`${key}=${params[key]}`);
                });
                const queryString = query.join("&");

                url += `?${queryString}`;

                return new Promise((resolve, reject) => {
                    const xhr = new XMLHttpRequest();
                    xhr.open(method, url, true);
                    xhr.responseType = "json";

                    xhr.onreadystatechange = () => {
                        if (xhr.readyState !== 4) {
                            return;
                        }

                        if (xhr.status >= 200 && xhr.status < 300) {
                            const response = {
                                data: xhr.response,
                                status: xhr.status,
                                statusText: xhr.statusText,
                            };
                            resolve(response);
                        } else {
                            reject(
                                new Error(
                                    "請求失敗 status code = " + xhr.status
                                )
                            );
                        }
                    };

                    if (method === "GET" || method === "DELETE") {
                        xhr.send(null);
                    } else {
                        xhr.setRequestHeader(
                            "Content-Type",
                            "application/json;charset=utf-8"
                        );
                        xhr.send(JSON.stringify(data));
                    }
                });
            }

            function testGet() {
                axios({
                    url: "http://localhost:3000/users",
                    // url: "http://localhost:3000/users1",
                    params: { age: 18, gender: "female" },
                })
                    .then((response) => {
                        console.log("get 成功", response.data, response);
                    })
                    .catch((error) => {
                        console.log("get 失敗", error.message);
                    });
            }

            function testPost() {
                axios({
                    url: "http://localhost:3000/users",
                    // url: "http://localhost:3000/users1",
                    method: "POST",
                    data: { name: "john", age: 30, gender: "male" },
                })
                    .then((response) => {
                        console.log("post 成功", response.data, response);
                    })
                    .catch((error) => {
                        console.log("post 失敗", error.message);
                    });
            }

            function testPut() {
                axios({
                    url: "http://localhost:3000/users/1",
                    // url: "http://localhost:3000/users1",
                    method: "PUT",
                    data: { name: "andy", age: 1, gender: "male" },
                })
                    .then((response) => {
                        console.log("put 成功", response.data, response);
                    })
                    .catch((error) => {
                        console.log("put 失敗", error.message);
                    });
            }

            function testDelete() {
                axios({
                    url: "http://localhost:3000/users/1",
                    // url: "http://localhost:3000/users1",
                    method: "DELETE",
                })
                    .then((response) => {
                        console.log("delete 成功", response.data, response);
                    })
                    .catch((error) => {
                        console.log("delete 失敗", error.message);
                    });
            }
        </script>
    </body>
</html>

參考資料


Similar Posts

Content