axios攻略

Axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。

Features

  • 從瀏覽器中創建 XMLHttpRequests
  • 從 node.js 創建 http 請求
  • 支持 Promise API
  • 攔截請求和響應
  • 轉換請求數據和響應數據
  • 取消請求
  • 自動轉換 JSON 數據
  • 客戶端支持防禦 XSRF

axios有兩種用法。

// 爲給定 ID 的 user 創建請求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  
// 也可以通過 params 對象傳遞參數
axios.get(‘/user’, {
	params: {ID: 12345}
}).then(response => {
	console.log(response);
}).catch(error => {
	console.log(error);
});
// 發送 POST 請求
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
}).then(response => {
});

axios的響應結構

{
  // `data` 由服務器提供的響應
  data: {},

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

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

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

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

在實際請求後臺接口時,會要求前端傳入規定格式的數據,比如jsonaxios會在請求之前判斷傳值的類型,並以相應的content-type發送請求到後臺服務器。在這個過程中踩了不少坑,特此,做一個總結。

  1. 坑1
    在使用axios發送post請求時,默認的請求頭Content-Type的屬性值爲application/json,這個時候瀏覽器會分兩次發送請求,首先使用OPTION方法發送請來詢問服務對請求是否支持,若不支持,則報錯,終止請求的發送。
  2. 坑2
  • 如果用urlSearchParams對象傳遞參數,那麼content-type的值爲application/x-www-form-urlencoded;charset=utf-8
  • 如果用json對象傳遞參數,那麼content-type的值爲application/json;charset=utf-8
    axios的源碼
axios.create = function create(instanceConfig) {
  return createInstance(utils.merge(defaults, instanceConfig));
};

create方法就是把我們傳入的參數和默認參數合併,然後創建一個axios實例,我們再看看defaults這個配置對象

var utils = require('./utils');
var normalizeHeaderName = require('./helpers/normalizeHeaderName');
/* 這個表明默認的Content-Type就是我們想要的 */
var DEFAULT_CONTENT_TYPE = {
  'Content-Type': 'application/x-www-form-urlencoded'
};
/* 看方法名就知道,這個是設置ContentType用的(Content-Type沒有設置的時候) */
function setContentTypeIfUnset(headers, value) {
  if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
    headers['Content-Type'] = value;
  }
}
/* 這個是用來區別對待瀏覽器和nodejs請求發起工具的區別的 */
function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    // For browsers use XHR adapter
    adapter = require('./adapters/xhr');
  } else if (typeof process !== 'undefined') {
    // For node use HTTP adapter
    adapter = require('./adapters/http');
  }
  return adapter;
}
/* 這裏終於看到了萬衆期待的默認配置 */
var defaults = {
  adapter: getDefaultAdapter(),
  /* 這個transformRequest配置就厲害了
   * 官方描述`transformRequest` allows changes to the request data before it is sent to the server 
   * 這個函數是接受我們傳遞的參數,並且在發送到服務器前,可以對其進行更改
   * */
  transformRequest: [function transformRequest(data, headers) {
    normalizeHeaderName(headers, 'Content-Type');
    if (utils.isFormData(data) ||
      utils.isArrayBuffer(data) ||
      utils.isStream(data) ||
      utils.isFile(data) ||
      utils.isBlob(data)
    ) {
      return data;
    }
    if (utils.isArrayBufferView(data)) {
      return data.buffer;
    }
    /* 關鍵點1、如果用URLSearchParams對象傳遞參數,就可以用我們想要的Content-Type傳遞 */
    if (utils.isURLSearchParams(data)) {
      setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
      return data.toString();
    }
    /* 關鍵點2、這裏我們看到,如果參數Object的話,就是通過json傳遞 */
    if (utils.isObject(data)) {
      setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
      return JSON.stringify(data);
    }
    return data;
  }],
  transformResponse: [function transformResponse(data) {
    /*eslint no-param-reassign:0*/
    if (typeof data === 'string') {
      try {
        data = JSON.parse(data);
      } catch (e) { /* Ignore */ }
    }
    return data;
  }],
  timeout: 0,
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  maxContentLength: -1,
  validateStatus: function validateStatus(status) {
    return status >= 200 && status < 300;
  }
};
defaults.headers = {
  common: {
    'Accept': 'application/json, text/plain, */*'
  }
};
utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
  defaults.headers[method] = {};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});
module.exports = defaults;

綜上述,欲傳遞表單數據,則通過urlSearchParams對象。示例:

import axios from 'axios';

let param = new URLSearchParams();
param.append("username", "admin");
param.append("password", "admin");

axios({
	method:'post',
	url:'/login',
	data:param
}).then(response => { });

參考地址

  1. 坑3
    當沒有參數傳遞時,設置的content-type的無用。
    axios源碼如下:
 // Add headers to the request
    if ('setRequestHeader' in request) {
      utils.forEach(requestHeaders, function setRequestHeader(val, key) {
        if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
          // Remove Content-Type if data is undefined
          delete requestHeaders[key];
        } else {
          // Otherwise add header to the request
          request.setRequestHeader(key, val);
        }
      });
    }

參考地址

  1. 坑4
    參考鏈接

  2. 坑5

this.$axios({
	method:'get',
    url:'/api/portal/login?loginName='+this.loginName+'&password='+this.password
}).then((response)=>{
    console.log(response);
})

這種方式請求頭中content-type的值爲application/json;charset=UTF-8

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章