Vue學習筆記(二)------axios學習

靜水流深醬發表於2019-04-20

Vue學習筆記(二)------axios學習
axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。

axios的功能和特徵:
  • 從瀏覽器中建立XMLHttpRequests
  • 從node.js中建立http請求
  • 支援PromiseAPI
  • 攔截請求和響應
  • 轉換請求資料和響應資料
  • 取消請求
  • 自動轉化JSON資料
  • 客戶端支援防禦XSRF
在專案中安裝axois

使用npm

npm   install  axios --save
複製程式碼

使用cdn

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
複製程式碼
使用demo
  • 執行GET請求,當執行GET方式時,如果攜帶請求引數,請求引數可以有兩種方式:

    axios.get('/user?ID=12121').then((response)=> {
        //response
    }).catch((error)=> {
        //error
    });
    或者
    axios.get('/user',{
        params: {
            ID: 12121
        }
    }).then((response)=> {
        //response
    }).catch((error)=> {
        //error
    });
    複製程式碼
  • 執行POST請求

    axios.post('/user',{
        name: '12121'
    }).then((response) => {
        //reponse
    }).catch((error) => {
        //error
    });
    複製程式碼
  • 執行多個併發請求

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.get/post這種寫法,這種寫法稍微有點麻煩,可以通過這種寫法,通過axios傳遞相關配置來建立請求。同時axios的預設的請求方式為GET方式。

axios({
    url: apiURL,
    method: method,
    timeout: timeout,
    data: data,
    params: params,
    headers: {
        'Content-Type': 'application/json',
        'token': window.sessionStore.getItem('token') || ''
    }
});
複製程式碼

當處理併發的方式時:

  • axios.all(iterable)
  • axios.spread(callback)
同時axios也支援通過自定義配置建立一個axios示例

語法: axios.create([config])

var instance = axios.create({
   baseURL: 'https://some-domain.com/api/',
   timeout: 1000,
   headers: {'X-Custom-Header': 'foobar'} 
});
複製程式碼

相關的請求配置

這些是建立請求時可以用的配置選項。只有 url 是必需的。如果沒有指定 method,請求將預設使用 get 方法。

//'url'是用於請求伺服器的URL
url: '/user',

//'method'是建立請求時使用的方法
method: 'get', //預設是get
    
//'baseUrl'將自動加在'url'前面,除非'url'是一個絕對url
//它可以通過設定一個 `baseURL` 便於為 axios 例項的方法傳遞相對 URL
baseURL: 'https://some-domain.com/api/',

//'transformRequest'允許向伺服器傳送前,修改請求資料
//只能用在put、post、patch這幾個請求方法
//後面陣列中的函式必須返回一個字串,或ArrayBuffer,或Stream
transformRequest: [function (data){
   //對data進行任意轉換處理
    return  data;
}],

//'transformResponse'在傳遞then/catch前,允許修改響應資料
transformResponse: [function (data){
   // 對data進行任意的轉換
    return  data;
}],
    
//'headers'是即將被髮送的自定義請求頭
headers: {'X-Requested-With': 'XMLHttpRequest'},
    
//'params'是即將與請求一起傳送的url引數
//必須是一個無格式物件(plain object)或 URLSearchParams物件
params: {
  ID: 12345        
},
// `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'})
},
    
// 'data'是作為請求主體被髮送的資料
// 只適用於這些請求方法(put,post,patch)
// 在沒有設定 `transformRequest` 時,必須是以下型別之一:
// string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 瀏覽器專屬:FormData, File, Blob
// - Node 專屬: Stream 
data: {
 name: '1212'       
},
    
// `timeout` 指定請求超時的毫秒數(0 表示無超時時間)
// 如果請求話費了超過 `timeout` 的時間,請求將被中斷
timeout: 1000,
    
// `withCredentials` 表示跨域請求時是否需要使用憑證
withCredentials: false, // 預設的
    
// `adapter` 允許自定義處理請求,以使測試更輕鬆
// 返回一個 promise 並應用一個有效的響應 (查閱 [response docs](#response-api)).
adapter: function (config) {
   /* ... */
},

// `auth` 表示應該使用 HTTP 基礎驗證,並提供憑據
// 這將設定一個 `Authorization` 頭,覆寫掉現有的任意使用 `headers` 設定的自定義 `Authorization`頭
auth: {
  username: 'janedoe',
  password: 's00pers3cret'
},
    
// 'responseType'表示伺服器響應的資料型別,可以是arraybuffer,blob,document,json,text,stream
responseType: 'json',   
複製程式碼
響應結構

某個請求的響應包含以下資訊:

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

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

  // `statusText` 來自伺服器響應的 HTTP 狀態資訊
  statusText: 'OK',

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

  // `config` 是為請求提供的配置資訊
  config: {}
}
複製程式碼

在實際的開發過程中後臺的介面會遵循RESTful規範,同時會自己封裝資料的返回格式,例如是下面這種格式:

img

也就是說我們取出的資料是從response.data中去拿到,然後按一定的格式取,一般後臺的資料的封裝格式如下:

新建一個util的包:

å¨è¿éæå
¥å¾çæè¿°

MessageEntity類:

package com.ssm.util;
import lombok.Data;

@Data
public class MessageEntity<T> {
    private Integer code;
    private String msg;
    private T data;
    private Integer total;
}

複製程式碼

MessageCode類:

package com.ssm.util;

public enum MessageCode {

    SYSTEM_CODE(500, "系統錯誤");

    private Integer code;
    private String message;

    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    MessageCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
複製程式碼

ResultForma類:

package com.ssm.util;

public class ResultFormat {

    public static MessageEntity success() {
        return success(null);
    }

    public static <T> MessageEntity<T> success(T t){
        MessageEntity msg = new MessageEntity();
        msg.setCode(200);
        msg.setMsg("操作成功");
        msg.setData(t);
        return msg;
    }

    public static  MessageEntity error(MessageCode message) {
        MessageEntity msg = new MessageEntity();
        msg.setCode(message.getCode());
        msg.setMsg(message.getMessage());
        return msg;
    }
}
複製程式碼
配置預設值
  • 全域性的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';
複製程式碼
  • 自定義例項預設值
// 建立例項時設定配置的預設值
var instance = axios.create({
  baseURL: 'https://api.example.com'
});

// 在例項已建立後修改預設值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
複製程式碼
  • 配置的優先順序

配置會以一個優先順序進行合併。這個順序是:在 lib/defaults.js 找到的庫的預設值,然後是例項的 defaults 屬性,最後是請求的 config 引數。後者將優先於前者。這裡是一個例子:

// 使用由庫提供的配置的預設值來建立例項
// 此時超時配置的預設值是 `0`
var instance = axios.create();

// 覆寫庫的超時預設值
// 現在,在超時前,所有請求都會等待 2.5 秒
instance.defaults.timeout = 2500;

// 為已知需要花費很長時間的請求覆寫超時設定
instance.get('/longRequest', {
  timeout: 5000
});
複製程式碼
攔截器

在請求或響應被 thencatch 處理前攔截它們。

// 新增請求攔截器
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 myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
複製程式碼
取消

可以使用 CancelToken.source 工廠方法建立 cancel token,像這樣:

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原始碼學習

找到axios下面的lib/axios.js檔案

Vue學習筆記(二)------axios學習

lib/axios.js中程式碼建立例項程式碼分析:

// lib/axios.js
function createInstance(defaultConfig) {
  // 建立一個Axios例項
  var context = new Axios(defaultConfig);

  // 以下程式碼也可以這樣實現:var instance = Axios.prototype.request.bind(context);
  // 這樣instance就指向了request方法,且上下文指向context,所以可以直接以 instance(option) 方式呼叫 
  // Axios.prototype.request 內對第一個引數的資料型別判斷,使我們能夠以 instance(url, option) 方式呼叫
  var instance = bind(Axios.prototype.request, context);

  // 把Axios.prototype上的方法擴充套件到instance物件上,
  // 這樣 instance 就有了 get、post、put等方法
  // 並指定上下文為context,這樣執行Axios原型鏈上的方法時,this會指向context
  utils.extend(instance, Axios.prototype, context);

  // 把context物件上的自身屬性和方法擴充套件到instance上
  // 注:因為extend內部使用的forEach方法對物件做for in 遍歷時,只遍歷物件本身的屬性,而不會遍歷原型鏈上的屬性
  // 這樣,instance 就有了  defaults、interceptors 屬性。(這兩個屬性後面我們會介紹)
  utils.extend(instance, context);

  return instance;
}

// 接收預設配置項作為引數(後面會介紹配置項),建立一個Axios例項,最終會被作為物件匯出
var axios = createInstance(defaults);
複製程式碼
  • 攔截器 interceptors

    攔截器分為請求攔截器(interceptors.request)和響應攔截器(interceptors.response)。

    請求攔截器(interceptors.request)是指可以攔截住每次或指定http請求,並可修改配置項 ;

    響應攔截器(interceptors.response)是指http請求後攔截,並可修改返回結果項;

  • 資料轉換器

    資料轉換器分為請求轉換器和響應轉換器,顧名思義: 請求轉換器(transformRequest)是指在請求前對資料進行轉換, 響應轉換器(transformResponse)主要對請求響應後的響應體做資料轉換。

  • http請求介面卡

  • config配置項

axios流程圖

img

axios多種使用方式:
  • 第1種使用方式:axios(option)
axios({
  url,
  method,
  headers,
})
複製程式碼
  • 第2種使用方式:axios(url[, option])
axios(url, {
  method,
  headers,
})
複製程式碼
  • 第3種使用方式(對於get、delete等方法):axios[method](url[, option])
axios.get(url, {
  headers,
})
複製程式碼
  • 第4種使用方式(對於post、put等方法):axios[method](url[, data[, option]])
axios.post(url, data, {
  headers,
})
複製程式碼
  • 第5種使用方式:axios.request(option)
axios.request({
  url,
  method,
  headers,
})
複製程式碼
使用者配置項物件config

http請求介面卡、請求地址、請求方法、請求頭header、 請求資料、請求或響應資料的轉換、請求進度、http狀態碼驗證規則、超時、取消請求等。可以發現,幾乎axios所有的功能都是通過這個物件進行配置和傳遞的, 既是axios專案內部的溝通橋樑,也是使用者跟axios進行溝通的橋樑。

import axios from 'axios'

// 第1種:直接修改Axios例項上defaults屬性,主要用來設定通用配置
axios.defaults[configName] = value;

// 第2種:發起請求時最終會呼叫Axios.prototype.request方法,然後傳入配置項,主要用來設定“個例”配置
axios({
  url,
  method,
  headers,
})

// 第3種:新建一個Axios例項,傳入配置項,此處設定的是通用配置
let newAxiosInstance = axios.create({
  [configName]: value,
})

複製程式碼
跨域攜帶cookie
import axios from 'axios'

axios.defaults.withCredentials = true;
複製程式碼
在react專案中對axios簡單封裝使用

命名三個檔案Api.js、ApiURL.js、ApiIp.js,其中ApiIp.js是用來獲取伺服器ip地址的,ApiURL.js是用來拼裝ip地址和介面路徑的,當然這個可以使用baseURL來實現也可以,即:axios.defaults.baseURL = 'api.example.com';

Api.js的實現

import axios from 'axios';
import {notification} from 'antd';
import * as ApiURL from 'src/HttpClientRequest/ApiURL';

const key = 'keepOnlyOne';

/**
 * 資料請求公共方法
 * @param apiURL      介面請求路徑
 * @param configObj   使用者傳入配置的引數
 * @returns {Promise<any>}
 */

function getDataFromServer(apiURL, configObj) {

    // 獲取使用者傳入的介面配置引數
    let {
        method = 'get',
        data = {},
        timeout = 3000,
        params = {}
    } = configObj;

    return new Promise(function (resolve, reject) {
        axios({
            url: apiURL,
            method: method,
            timeout: timeout,
            data: data,
            params: params,
            headers: {
                'Content-Type': 'application/json',
                'token': window.sessionStore.getItem('token') || ''
            }
        }).then((response) => {
            if (response) {
                if (response.data && response.data.code) {
                    resolve(response);
                } else {
                    notification.error({
                        key,
                        message: '操作失敗',
                        description: '資料格式有誤'
                    });
                    resolve(response);
                }
            } else {
                notification.error({
                    key,
                    message: '操作失敗',
                    description: '伺服器錯誤'
                });
                resolve(response);
            }
        }).catch((error) => {
            notification.error({
                key,
                message: '操作失敗',
                description: '網路異常,請稍後重試'
            });
            reject(error);
        });
    });
}


export function login(configObj) {
    return getDataFromServer(ApiURL.LOGIN, configObj);
}
複製程式碼

ApiURL.js

import API_IP from './ApiIp';

// 登入介面地址
export const LOGIN = `${API_IP}/index/login`;
複製程式碼

ApiIp.js

// 獲取當前瀏覽器的地址
const interfaceIp = window.location.host;
const imageAddrassIp = window.location.hostname;

// 獲取當前瀏覽器的協議
const browserProtocol = window.location.protocol;

// 進行伺服器請求地址的封裝
const serverInterfaceIp = `${browserProtocol}//${interfaceIp}`;
const serverImageIp = `${browserProtocol}//${imageAddrassIp}`;

// 對外提供的請求地址(相容生產環境和開發環境)
export const API_IP = process.env.NODE_ENV === 'development' ? 'http://121.0.0.1:8080' : serverInterfaceIp;
export const IMAGES_IP = process.env.NODE_ENV === 'development' ? 'http://121.0.0.1' : serverImageIp;
複製程式碼

參考文章:juejin.im/post/5cb5d9…

相關文章