Axios二次封裝

axios是一個基於Promise的http庫,能夠用在瀏覽器和node.js中。同時也是對原生瀏覽器請求XMLHttpRequest的封裝,支持Promise的APi請求,避免了回掉地獄問題,能夠對請求進行攔截,在發出請求前對請求參數進行修改,接受服務器響應時,也能夠根據返回的code進行統一的處理,且客戶端支持防護XSRF。能夠開箱即用,可是在實際項目時,須要對axios進行二次封裝前端

實例 Or defaults

對 axios 進行二次封裝由兩種方式,一種是建立一個axios實例,另一種是直接修改axios的defaultsnode

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

固然在使用第一種建立一個實例時,也能夠設置這個實例的defaults,就像這樣webpack

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

設置baseURL

在先後端分離項目,每每須要定義一個全局變量來聲明後臺的接口地址,通常我會選擇經過 webpack 的 definePlugin 插件來給頁面設置全局變量,而且根據不一樣的環境傳遞不一樣的值。好比說後臺的接口部署在了 http://localhost:3000 那麼首先使用 webpack 定義一個叫 SERVICE 的全局變量ios

new webpack.DefinePlugin({
    SERVICE: "'http://localhost:3000'"
})
複製代碼

而後就能夠在頁面中使用這個全局變量,固然若是是在ts項目下的話,直接使用SERVICE會抱一個未定義的錯,那麼只須要在使用SERVICE的文件中申明一下便可,未使用ts 的能夠跳過這句聲明。web

import axios from 'axios';
// ts 下使用 須要先聲明
declare const SERVICE: string;
axios.defaults.baseURL = SERVICE;
複製代碼

設置Content-type

在 post 請求和 put 請求中,須要在請求頭裏設置一下content-type 爲 application/x-www-form-urlencodedjson

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded';
複製代碼

設置withCredentials

跨域請求時,默認是不會攜帶cookie的,這就致使了在先後端分離項目中,作一個登陸的頁面,登陸完以後跳轉主頁面,可是主頁面中請求的接口未檢測到用戶已登陸那麼就會跳回登陸頁面,大概時這樣的場景。那麼原因就是由於axios在發起請求時沒有攜帶cookie的,經過設置withCredentials爲true 來解決axios

axios.defaults.withCredentials = true;
複製代碼

請求攔截 request處理

能夠經過對請求的攔截,修改參數,對參數進行序列化處理,防止XSRF攻擊。序列化使用 qs來實現,qs的優勢是能夠對深層次的json array 等複雜類型進行序列化。後端

axios.interceptors.request.use((config: any): any => {
    // 給請求添加請求時間
    if (config.url.indexOf('?') !== -1) {
        config.url += `&t=${new Date().getTime()}`;
    } else {
        config.url += `?t=${new Date().getTime()}`;
    }
    // `transformRequest` 容許在向服務器發送前,修改請求數據
    // 只能用在 'PUT', 'POST''PATCH' 這幾個請求方法
    // 後面數組中的函數必須返回一個字符串,或 ArrayBuffer,或 Stream
    config.transformRequest = [(data: any, headers: any) => {
        return qs.stringify(data, {
            allowDots: true
        })
    }];
    // `paramsSerializer` 是一個負責 `params` 序列化的函數
    config.paramsSerializer = (params: any) => {
        return qs.stringify(params, {
            arrayFormat: 'repeat'
        })
    };
    return config;
}, (error: any) => {
    return Promise.reject(error);
});
複製代碼

對response進行處理

有這麼一個場景,當接口返回的code爲2時,代表用戶未登陸,這時須要前端對請求的response返回的code進行判斷,那麼一個請求一個請求的判斷確定是會很麻煩的,哪一個請求忘了加判斷就完蛋了,因此axios提供了對響應進行攔截的操做。api

axios.interceptors.response.use((response: any): any => {
    const { data } = response;
    if(data.code === 2){
        window.location.href = `/login?from=${window.location.pathname}`;
    }
    return response;
}, (error: any) => {
    Promise.reject(error);
});
複製代碼

axios常規操做

GET請求

get請求,對於須要參數的get請求,請必定要將參數放在 params 裏,否則你會吃虧的。使用場景以下,獲取一個郵件的id,mailId是一個很是長的一串各類字符組成的,恰巧這裏麪包含了一些 . 或者 \ 或者 : 啥的,具體的我也不知道,最後致使的緣由是這個郵箱的mailID穿不到後臺,由於這個參數直接放在路由後面是有問題的,因此請直接講參數放在params裏,由於上面已經對params裏的參數進行了處理。跨域

axios.get('/api/info',{
    params: {
        id: 1
    }
}).then(res => {

}).catch(err => {

})
複製代碼

POST請求

axios.post('/api/info',{
    username: 'haha',
    password: '123456'
}).then(res => {

}).catch(err => {

})

複製代碼

delete 請求相似於get請求 put請求相似於post請求

鏈式調用

axios.get('/api/info',{
    params: {
        id: 1
    }
}).then(res => {
    return axios.post('/api/info',{
        username: 'haha',
        password: '123456'
    });
}).then(res => {

}).catch(err => {

})
複製代碼

axios.all

Promise.all 相似,用於多個請求並罰處理,等待請求所有完成時執行回調,而且回調參數爲一個數組,數組裏的順序與請求的順序是一致的,也就是說他是按順序將返回值存進去的

axios.all([
    axios.get('/api/info',{
        params: {
            id: 1
        }
    }),
    axios.post('/api/info',{
        username: 'haha',
        password: '123456'
    });
]).then(resArray => {
    // resArray[0] 爲axios.get('/api/info') 的res
    // resArray[1] 爲axios.post('/api/info') 的res
}).catch(err => {

})
複製代碼

完整代碼-模塊化開發

封裝完了以後將axios導出,其餘的頁面直接引用該axios就行。完整代碼以下

// request.js
import axios from 'axios';
import * as qs from 'qs';

declare const SERVICE: string;

axios.defaults.baseURL = SERVICE;
axios.defaults.withCredentials = true;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded';

// qs 序列化 防止XSRF攻擊 能夠對深層次的json array進行序列化
axios.interceptors.request.use((config: any): any => {
    if (config.url.indexOf('?') !== -1) {
        config.url += `&t=${new Date().getTime()}`;
    } else {
        config.url += `?t=${new Date().getTime()}`;
    }
    // `transformRequest` 容許在向服務器發送前,修改請求數據
    // 只能用在 'PUT', 'POST''PATCH' 這幾個請求方法
    // 後面數組中的函數必須返回一個字符串,或 ArrayBuffer,或 Stream
    config.transformRequest = [(data: any, headers: any) => {
        return qs.stringify(data, {
            allowDots: true
        })
    }];
    // `paramsSerializer` 是一個負責 `params` 序列化的函數
    config.paramsSerializer = (params: any) => {
        return qs.stringify(params, {
            arrayFormat: 'repeat'
        })
    };
    return config;
}, (error: any) => {
    return Promise.reject(error);
});

axios.interceptors.response.use((response: any): any => {
    const { data } = response;
    if(data.code === 2){
        window.location.href = `/login?from=${window.location.pathname}`;
    }
    return response;
}, (error: any) => {
    Promise.reject(error);
});

export default axios;
複製代碼
// action.js
import axios from './request';
axios.get('')
    .then(res = > {
        // 業務代碼
    })
    .catch(err => {
        // 業務代碼
    })
複製代碼
相關文章
相關標籤/搜索