請求 - axios

實際應用示例

  • 前端不須要作統一的接口防重
    • 前端沒法經過判斷接口是否返回來釋放按鈕(由於能夠手動刷新頁面,將致使刷新前請求丟失)
    • 後端對接口作了防重

經過增長時間戳避免IE9的get請求緩存問題

axios.interceptors.request.use(function (response) {
    if (method === 'get' && isIE) {
        config.url += `${!config.url.includes('?') ? '?' : '&'}timeStamp=${new Date().getTime()}`;
    }
})

添加響應攔截器,統一處理異常請求狀態

axios.interceptors.response.use(
    res => {
      // 對響應數據進行處理
      return res
    },
    err => {
      const errInfo = err.response;
      if (errInfo) {
        switch (errInfo.status) {
          case 403: 
            // 403 服務器拒絕請求。
            break;
          case 404:
            // 404 服務器找不到請求的網頁。
            break;
          case 401:
            // 401 請求要求身份驗證。
            break;
          case 400:
            // 服務器不理解請求的語法。
            break;
          case 500:
            // 服務器遇到錯誤,沒法完成請求。
            break;
        }
      }
      return Promise.reject(err);
    }
  );

—————————————————————————————————————————————————————————

使用配置建立自定義實例

配置會以一個優先順序進行合併

  • 在 lib/defaults.js 找到的庫的默認值
  • 經過 axios.defaults 修改的全局默認值
  • 而後是實例的 defaults 屬性(defaults 屬性:實例的默認屬性。有兩種方法設置,一種 create 建立實例時傳入,一種建立實例後經過 defaults 屬性修改)
  • 最後是請求的 config 參數
// 經過 defaults 設置全局的 axios 默認值
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;    // 影響全部?
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';    // 隻影響post請求?
// 能夠自定義defaults下的屬性,在請求的其餘地方經過請求對象獲取該值
axios.defaults.loginUrl = "http://ihrsit.midea.com:8088/login/ihr/login"; 

// 建立實例時設置配置的默認值
const instance = axios.create({
  baseURL: 'https://api.example.com'
});

// 在實例已建立後修改默認值
instance.defaults.timeout = 2500; // 如今,在超時前,全部請求都會等待 2.5 秒
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN; // 設置所有的請求的請求頭?,注意這裏的common應該是值所有的請求類型


// 請求時的 config 參數
instance.get('/longRequest', {
  timeout: 5000
});

可配置項

{
  // `url` 是用於請求的服務器 URL
  url: '/user',

  // `method` 是建立請求時使用的方法
  method: 'get', // 默認是 get

  // `baseURL` 將自動加在 `url` 前面,除非 `url` 是一個絕對 URL。
  // 它能夠經過設置一個 `baseURL` 便於爲 axios 實例的方法傳遞相對 URL
  baseURL: 'https://some-domain.com/api/',

  // `headers` 是即將被髮送的自定義請求頭
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `timeout` 指定請求超時的毫秒數(0 表示無超時時間)默認爲0
  // 若是請求話費了超過 `timeout` 的時間,請求將被中斷
  // 這個超時時間在谷歌中彷佛無效?,待驗證
  timeout: 1000,

  // `withCredentials` 表示跨域請求時是否須要使用憑證(憑證,例如cookie)
  // 指訪問的這個跨域接口,能不能設置本身域下的cookie,若是爲爲false,那麼不容許設置該接口域名下的cookie。
  // 經過設置爲true而得到的接口,一樣遵照同源策略。當前窗口下的其餘域名是不可以訪問這個cookie的
  // 存在兼容性問題
  withCredentials: false, // 默認的

  // `responseType` 表示服務器響應的數據類型,能夠是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // 默認的

  // XSRF(跨站請求僞造)網站 B 使用 get 請求網站 A 的接口時,會自動帶上 A 的 COOKIE,若是 A 的 token 保存在 COOKIE 中就會被冒用身份。
  // 例如:在一個論壇中,某人上傳了攜帶 XSRF 攻擊的圖片(該圖片的 src 實際爲 A 網站的接口),當其餘用戶加載這個圖片時,攜帶 COOKIE 的請求就會被髮起,身份可能被冒用。
  // 防範方法
        // 經過請求頭Referer(請求來源域名)判斷請求是否來自於合法服務器
        // 在HTTP請求頭部添加自定義key,通常爲 csrftoken 並把 token 值放入其中
  // `xsrfCookieName` 是用做 xsrf token 的值的cookie的名稱(該值放在cookie中?放在cookie有什麼意義,不是也會被跨域攻擊?)
  // xsrf token 彷佛和頂部的csrftoken是同一個概念
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` 是承載 xsrf token 的值的 HTTP 頭的名稱
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默認的

  // `maxContentLength` 定義容許的響應內容的最大尺寸
  maxContentLength: 2000,    // 以什麼爲單位?

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————改變請求響應參數

  // `params` 是即將與請求一塊兒發送的 URL 參數(會被拼接到URL的?後面)?
  // 必須是一個無格式對象或 URLSearchParams 對象
  // 無格式對象,plain object經過字面量形式或者new Object()形式定義的對象。特色是它的原型直接指向根原型,不存在多級原型鏈
  // URLSearchParams URL查詢字符串對象(知足URL查詢格式的字符串?)
  params: {
    ID: 12345
  },

  // `paramsSerializer` 是一個負責 `params` 序列化的函數
  paramsSerializer: function(params) {
    // Qs.stringify:Qs庫的一個方法,把一個參數對象格式化爲一個字符串
    return Qs.stringify(params, {arrayFormat: 'brackets'})    
  },

  // `data` 是做爲請求主體被髮送的數據
  // 只適用於這些請求方法 'PUT', 'POST', 和 'PATCH'
  // 在沒有設置 `transformRequest` 時,必須是如下類型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // ArrayBufferView 沒有特定的實體,是指一類二進制數據對象,叫類數組數據
  // - 瀏覽器專屬:FormData, File, Blob
  // Blob 二進制大對象
  // - Node 專屬: Stream
  data: {
    firstName: 'Fred'
  },

  // `transformRequest` 容許在向服務器發送前,修改請求數據
  // 只能用在 'PUT', 'POST' 和 'PATCH' 這幾個請求方法
  // 經過 axios.defaults.transformRequest = [function] 設置會致使get請求的數據也被修改
  // 後面數組中的函數必須返回一個字符串,或 ArrayBuffer(二進制數據緩衝區),或 Stream(流)
  // 默認轉爲 JSON 數據?
  transformRequest: [function (data) { // 這裏用了一個數組,是依次修改的意思嗎?
    // 對 data 進行任意轉換處理

    return data;
  }],

  // `transformResponse` 在傳遞給 then/catch 前,容許修改響應數據
  transformResponse: [function (data) {
    // 對 data 進行任意轉換處理

    return data;
  }],

  // `validateStatus` 定義對於給定的HTTP 響應狀態碼是 resolve 或 reject  promise 。若是 `validateStatus` 返回 `true` (或者設置爲 `null` 或 `undefined`),promise 將被 resolve; 不然,promise 將被 rejecte
  // 該函數能夠經過 http 相應狀態碼來設置接口對應的 promise 的狀態,當 validateStatus 函數返回 true 時,promise 將被 resolve(成功); 不然,promise 將被 reject(失敗)
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默認的,當狀態碼200-300間時,axios返回resolve狀態的promise不然返回rejecte狀態的
  },

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————其餘方法

  // `onUploadProgress` 容許爲上傳處理進度事件
  onUploadProgress: function (progressEvent) {    // xhr.upload.onprogress事件的處理函數
    // XMLHttpRequest.upload 只讀對象,用來表示上傳的進度,做爲一個XMLHttpRequestEventTarget,能夠經過對其綁定事件來追蹤它的進度。
    // 能夠被綁定在upload對象上的事件監聽器以下:
    // onloadstart  獲取開始、onprogress 數據傳輸進行中、onabort 獲取操做終止、onerror  獲取失敗、onload 獲取成功、ontimeout  獲取操做在用戶規定的時間內未完成、onloadend  獲取完成(不論成功與否)
    // XMLHttpRequestEventTarget.onprogress 是在 XMLHttpRequest 完成以前週期性調用的函數。
    // XMLHttpRequest.onprogress = function (event) {
    //   event.loaded; // 週期性調用中接受到了多少信息?
    //   event.total; // 該請求一共有多少信息。?
    // };
    // 對原生進度事件的處理
  },

  // `onDownloadProgress` 容許爲下載處理進度事件
  onDownloadProgress: function (progressEvent) {
    // XMLHttpRequest 沒有對應的屬性指向下載對象,這個方法是如何實現的?
    // 對原生進度事件的處理
  },

  // `cancelToken` 指定用於取消請求的 cancel token(取消令牌)
  // cancelToken 指望傳入由構造函數 axios.CancelToken 返回的對象
  // 該構造函數接收一個函數做爲參數,並把取消方法 cancel 傳入這個函數中,當cancel被調用時請求就會被取消。
  //(生成的對象應該有某個屬性指向咱們傳入的函數,後文的例子是用獨立變量保存這個取消函數並不理想)
  cancelToken: new CancelToken(function (cancel) {    // CancelToken構造函數須要事先聲明,見下文中的取消專題
  })

  // `adapter` 容許自定義處理請求,以使測試更輕鬆
  // 返回一個 promise 並應用一個有效的響應 (查閱 [response docs](#response-api)).
  adapter: function (config) {
    /* ... */
  },

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————服務器

  // `auth` 表示應該使用 HTTP 基礎驗證,並提供憑據
  // 這將設置一個 `Authorization` 頭,覆寫掉現有的任意使用 `headers` 設置的自定義 `Authorization`頭。通常用在非瀏覽器上(用在代理服務器上?)
  // Authorization 請求消息頭含有服務器用於驗證用戶代理身份的憑證,一般會在服務器返回401 Unauthorized 狀態碼以及WWW-Authenticate 消息頭以後在後續請求中發送此消息頭。
  // 401 Unauthorized 狀態碼 : 表明該接口未經許可
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // `maxRedirects` 定義在 node.js 中 follow 的最大重定向數目
  // 若是設置爲0,將不會 follow 任何重定向
  // 這裏能夠定義一個接口被重定向的次數?
  maxRedirects: 5, // 默認的

  // `httpAgent` 和 `httpsAgent` 分別在 node.js 中用於定義在執行 http 和 https 時使用的自定義代理。容許像這樣配置選項:(???)
  // `keepAlive` 默認沒有啓用
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy' 定義代理服務器的主機名稱和端口
  // `auth` 表示 HTTP 基礎驗證應當用於鏈接代理,並提供憑據
  // 這將會設置一個 `Proxy-Authorization` 頭(給代理服務器的用於身份驗證的憑證),覆寫掉已有的經過使用 `header` 設置的自定義 `Proxy-Authorization` 頭。
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: : {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },
}

建立實例的方法

  • 當須要對各種型請求方式設置不一樣配置項時建立,僅僅只是統一修改全局配置用 axios.defaults 更方便
  • axios.create([config]) 使用自定義配置新建一個 axios 實例,實例繼承axios的全部方法
var instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000, // 以毫秒爲單位
  headers: {'X-Custom-Header': 'foobar'}
});
  • 如下是可用的實例方法。指定的配置將與實例的配置合併。
    • axios#request(config)
    • axios#get(url[, config])
    • axios#delete(url[, config])
    • axios#head(url[, config])
    • axios#options(url[, config])
    • axios#post(url[, data[, config]])
    • axios#put(url[, data[, config]])
    • axios#patch(url[, data[, config]])

使用 application/x-www-form-urlencoded 格式化數據

  • 默認狀況下,axios將JavaScript對象序列化爲JSON。
    • get 默認是 application/x-www-form-urlencoded,不會顯示 Content-Type,表現爲不可摺疊按鍵值顯示
    • post 默認爲 JSON,表現爲可摺疊對象
    • 當 axios.post 第二個參數是字符串時,默認爲 application/x-www-form-urlencoded,這個字符串做爲 name1=value1鏈的name
  • 要以application / x-www-form-urlencoded格式發送數據,您可使用如下選項之一。
    • 在請求頭的Content-type代表請求的數據格式(設置了請求頭彷佛並不會自動轉換格式)
    • application / x-www-form-urlencoded 編碼方式把數據轉換成一個字串(name1=value1&name2=value2…)(會自動檢測數據類型)

瀏覽器

  • 在瀏覽器中,您可使用URLSearchParams API
    • URLSearchParams 接口定義了一些實用的方法來處理 URL 的查詢字符串。
    • 兼容性在IE並不理想
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
  • 可使用qs庫編碼數據:
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  data: qs.stringify(data),
  url,
};
axios(options);

Node.js

  • 在node.js中,您可使用querystring模塊
    • querystring 模塊提供用於解析和格式化 URL 查詢字符串的實用工具。
const querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));

—————————————————————————————————————————————————————————

攔截器(分爲請求和攔截)

添加攔截器

// 添加請求攔截器
axios.interceptors.request.use(function (config) {
    // 在發送請求以前作些什麼
    // config 應該是請求的配置和傳參
    return config;

    // 還能夠返回 promise.reject 來拒絕請求
    return Promise.reject(error);
  }, function (error) {
    // 對請求錯誤作些什麼
    return Promise.reject(error);
  });

// 添加響應攔截器,能夠爲自定義 axios 實例添加攔截器
axios.interceptors.response.use(function (response) {
    // 對響應數據作點什麼
    return response;
  }, function (error) {
    // error.config 包含了 axios 請求的參數,包括 url 和 method
    // 對響應錯誤作點什麼
    return Promise.reject(error);
  });

移除攔截器

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
  • 能夠爲自定義 axios 實例添加攔截器

—————————————————————————————————————————————————————————

發起請求

axios.request(config):實際上全部aixos請求的建立都是request方法來實現的。

axios.request({
     url: "http://example.com",
     method: "get",
     headers:{
         Cookie: "cookie1=value; cookie2=value; cookie3=value;"
     } 
}).then(...)

axios(config):傳遞相關配置來建立請求

axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});
// 獲取遠端圖片
axios({
  method:'get',
  url:'http://bit.ly/2mTM3nY',
  responseType:'stream' // responseType表示指望服務器響應的數據類型
})
  .then(function(response) {
    // pipie nodejs中對流數據的一種操做
    // fs nodejs中文件對象
    // fs.createWriteStream 保存文件
  response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});

axios(url[, config]):發送 GET 請求

// 發送 GET 請求(默認的方法)
axios('/user/12345');

axios.get(url[, config])

axios.get('/user?ID=12345')
// 可寫爲
axios.get('/user', {
    params: {
      ID: 12345
    }
  })

axios.delete(url[, config])

axios.head(url[, config])

  • HEAD跟get很像,可是不返回響應體信息,用於檢查對象是否存在,並獲取包含在響應消息頭中的信息。

axios.post(url[, data[, config]])

  • post 向指定資源提交數據進行處理的請求,用於添加新的內容。
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })

axios.put(url[, data[, config]])

  • put 向指定資源位置上傳其最新的內容,用於修改某個內容。(存在則替換,不存在則建立。)

axios.patch(url[, data[, config]])

  • patch 用來更新局部資源,相對於put而言
  • PATCH是冪等的,冪等是指這個請求任意屢次執行所產生的影響均與一次執行的影響相同

—————————————————————————————————————————————————————————

併發

  • axios.all(iterable):當全部的請求都完成後,會收到一個數組,包含着響應對象,其中的順序和請求發送的順序相同,可使用 axios.spread 分割成多個單獨的響應對象(?)
  • axios.spread(callback)
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 的 cancel token API(取消令牌) 基於cancelable promises proposal(沒法兌現的promise建議),它還處於第一階段。
  • 取消後,在谷歌的控制檯中,請求狀態變爲canceled
  • 可使用 CancelToken.source 工廠方法建立 cancel token
var CancelToken = axios.CancelToken;    
var source = CancelToken.source();   // axios自帶的取消令牌,應該是經常使用方法的一種便捷入口而已,本質和new axios.CancelToken 返回實例是一致的

axios.get('/user/12345', {
  cancelToken: source.token // 設置令牌對象
}).catch(function(thrown) {    // 取消請求會進入catch
  if (axios.isCancel(thrown)) {    // isCancel判斷是否由axios發起的取消
    console.log('Request canceled', thrown.message);    // thrown.message來源於cancel函數的傳參,見最後
  } else {
    // 處理錯誤
  }
});

// 帶參數
axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 取消請求(message 參數是可選的)
source.cancel('Operation canceled by the user.');
  • 能夠經過傳遞一個 executor 函數到 CancelToken 的構造函數來建立 cancel token
var CancelToken = axios.CancelToken;
var cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函數接收一個 cancel 函數做爲參數
    cancel = c;
  })
});

// 取消請求
cancel();
  • 可使用同一個 cancel token 取消多個請求(應該是配置了同一個令牌的接口,能被同一個令牌取消)

—————————————————————————————————————————————————————————

錯誤處理

// 錯誤有如下幾種
// 請求發起失敗
// 請求發起成功,沒有任何響應(響應錯誤)
// 成功響應,響應返回 200 之外的值?
axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // 請求已經發起,服務器已經返回了響應狀態碼
      // 狀態碼不是 2xx 時(須要使用 validateStatus 配置選項定義一個自定義 HTTP 狀態碼的錯誤範圍。)
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // 響應錯誤時(請求已發出,未收到響應,例如超時)
      // `error.request` 在瀏覽器中是 XMLHttpRequest 實例
      // 在 node.js 中是 http.ClientRequest 實例 
      console.log(error.request);
    } else {
      // 請求發起錯誤(請求未正確發起)
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

—————————————————————————————————————————————————————————

響應結構

  • then
{
  // `data` 由服務器提供的響應
  data: {},    // 不必定爲對象

  // `status` 來自服務器響應的 HTTP 狀態碼
  status: 200,

  // `statusText` 來自服務器響應的 HTTP 狀態信息
  statusText: 'OK',

  // `headers` 服務器響應的頭
  headers: {},

  // `config` 是爲請求提供的配置信息
  config: {}

  // `request` 表明生成此相應請求的對象
  // 在node.js 中若是有重定向,它指向最後一個重定向產生的請求
  // 在瀏覽器中它是一個 XMLHttpRequest實例
  request: {}
}
  • 在使用 catch 時,或傳遞 rejection callback 做爲 then 的第二個參數時,響應能夠經過 error 對象獲取(catch函數中 error.response 返回完整的響應,包括staue等)
    • promise 中使用 catch 只是 then 的語法糖,實際就是 then(undefined, catchFun) 的簡易寫法
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);
    // 沒有response.request
  });

—————————————————————————————————————————————————————————

安裝

npm install axios

其餘

  • 請求類型執行一種直觀的接口類型說明,其實現邏輯仍是依賴於後端代碼。固然,能夠用公共的代碼對相同類型的接口作統一處理

—————————————————————————————————————————————————————————

相關文章
相關標籤/搜索