Axios源碼淺析

Axios簡介

基於Promise的HTTP客戶端,用於瀏覽器和node.jsjavascript

  • 支持瀏覽器端 ajax 請求
  • 支持從 node.js 發出http請求
  • 支持 Promise API
  • 支持攔截請求和響應
  • 轉換請求和響應數據
  • 取消請求
  • 自動轉換JSON數據
  • 客戶端支持防範XSRF

源碼目錄介紹

源碼架構

  • 建立一個 Axios 構造函數,添加默認配置,攔截器,原型上掛載請求方法
// core/axios.js
  // 構造Axios構造函數
  function Axios(instanceConfig) {
    this.defaults = instanceConfig;
    // 添加攔截器
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    };
  }
  // 實際請求方法
  Axios.prototype.request = function() {};
  Axios.prototype.getUri = function() {};

  // 沒有請求體 delete get head options
  Axios.prototype.get = function(url, config = {}) {
    return this.request(Object.assign(config, {
      method: 'get',
      url
    }))
  };

  // 有請求體 post put patch
  Axios.prototype.post = function(url, data, config = {}) {
    return this.request(Object.assign(config, {
      method: 'post',
      url,
      data
    }))
  };
複製代碼
  • 實例化一個Axios實例context,接着建立instance指向Axios.prototype.request方法,並綁定了上下文context
  • 經過extend方法把context中的原型方法和實例方法所有拷貝到instance上 ,返回instance
  • 建立一個默認實例,掛載快捷方法create,CancelToken,all等方法
// axios.js
  // 建立一個Axios實例,掛載輔助方法,並導出該混合對象
  function createInstance(defaultConfig = {}) {
    var context = new Axios(defaultConfig);
    var instance = bind(Axios.prototype.request, context);
    // Copy axios.prototype to instance
    utils.extend(instance, Axios.prototype, context)
    // copy context to instance
    utils.extend(instance, context)
    return intance
  }
  // create the default instance to be exported
  var axios = createInstance({})
  axios.Axios = Axios
  axios.create= function(config) {
    return createInstance(Object.assign(axios.defaults, config))
  }
  // 取消請求
  axios.Cancel = require('./cancel/Cancel')
  axios.CancelToken = require('./cancel/CancelToken')
  axios.isCancel = require('./cancel/isCancel')

  // Prmoise.all 的語法糖
  axios.all = Promise.all
  axios.spread = require('./helpers/spread')
複製代碼

🤔 如何實現 axios 所支持的的功能

支持 Node瀏覽器 端的 http 請求

  • 關鍵代碼java

  • 原理介紹node

    • 經過 process 區分出 Node 環境和瀏覽器環境
    • 瀏覽器環境使用 XMLHttpRquest 發起http請求,Node環境使用httphttps 模塊發起請求
    • 經過 Promise 包裝實現請求方法

請求響應攔截器

  • 關鍵代碼webpack

    • lib/core/InterceptorManager.js
    • lib/core/Axio.js
  • 攔截器運行示意ios

Promise
  .then(request[1].fulfilled, request[1].rejected)
  .then(request[0].fulfilled, request[1].rejected)
  .then(dispatchRequest, undefined)
  .then(response[0].fulfilled, response[0].rejected)
  .then(response[1].fulfilled, response[1].rejected)
  .then() // user opt
複製代碼
  • 原理介紹
    • 實現一個攔截器類中維護一個數組,添加攔截器方法 use , 移除攔截器方法 eject, 遍歷攔截器方法 forEach
    • 利用數組 unshift, push 方法,添加請求攔截器和響應攔截器
    • 利用 Promise.then 鏈式調用添加的攔截器

若是你們有了解過Koa的中間件原理,可能會發現很類似git

轉換請求和響應數據

  • 關鍵代碼github

  • 原理介紹web

    • 默認配置中內置默認 transformRequest, transformResponse 方法,處理常見狀況
    • 編寫transformData 方法,遍歷多個轉換器,處理數據
function transformData(data, headers, fns) {
    /*eslint no-param-reassign:0*/
    utils.forEach(fns, function transform(fn) {
      data = fn(data, headers);
    });

    return data;
  };
複製代碼
  • dispatchRequest 請求前,調用 transformData 調用全部的請求轉化器處理請求數據
  • 請求完成後,調用 transformData 調用全部的響應轉化器處理響應數據

取消請求

  • 關鍵代碼ajax

  • 原理介紹axios

    • 建立一個 CancelToken 構造函數接受一個 executor 函數,內部實例化一個 pending 狀態的 Promise 對象,而後用一個 resolvePromise 變量指向 resolve 函數。
    • 接着執行 executor 函數,傳入一個 cancel 函數,在 cancel 函數內部,會調用 resolvePromisePromise 對象從 pending 狀態變爲 resolved 狀態。
    • request 請求中的 resolvePromise.then 被執行

客戶端支持防範 XSRF

  • XSRF介紹

  • 防範方法

    • 驗證請求 referer, 但因爲 referer 也能夠僞造,做用有限
    • 服務器端生成 token,並經過 set-cookie 的方式種到客戶端,而後客戶端發送請求的時候,從 cookie 中對應的字段讀取出 token,而後添加到請求 headers 中。因爲這個 token 比較難僞造,因此就能區分這個請求是不是用戶正常發起的。
  • 關鍵代碼

  • 原理介紹

    • 首先判斷若是是配置 withCredentialstrue 或者是同域請求,咱們纔會請求 headers 添加 xsrf 相關的字段。
    • 若是判斷成功,嘗試從 cookie 中讀取 xsrftoken 值。
    • 若是能讀到,則把它添加到請求 headersxsrf 相關字段中。

完整流程

如何開發一個 Axios 這樣的開源工具庫

  • 需求分析,例如 Axios 支持的 feature,就是需求分析
  • 項目搭建,完整的構建發佈流程和完備測試case能夠增長開發效率和信任度, Axios 採用 grunt 構建 (如今更多會選擇 webpack, rollup, parcel 等),並具備完備的測試,示例代碼。
  • API 設計,肯定需求以後,必定要花時間設計友好,易用的API, Axios 就有多種多樣的使用方式,足夠靈活。
  • 實際編碼,這部分多是花時間最少的哦😯~
  • 完整的測試用例和示例,Axios 的測試case很是之多,example 下的示例代碼也很豐富
  • 詳細的文檔,列出使用的方法,可能存在的問題,
  • issue 模板,方便用戶反饋使用中的問題

結語

閱讀社區優秀的源碼,有助於開拓視野,作到知其因此然,遇到問題才能輕鬆解決~

相關文章
相關標籤/搜索