十. Axios網絡請求封裝

1. 網絡模塊的選擇

Vue中發送網絡請求有很是多的方式,那麼在開發中如何選擇呢?javascript

選擇一:傳統的Ajax是基於XMLHttpRequest(XHR)html

爲何不用它呢?很是好解釋配置和調用方式等很是混亂,編碼起來看起來就很是蛋疼。因此真實開發中不多直接使用而是使用jQuery-Ajax。前端

選擇二:使用jQuery-Ajaxvue

相對於傳統的Ajax很是好用,爲何不選擇它呢?首先咱們先明確一點,在Vue的整個開發中都是不須要使用jQuery了,那麼就意味着爲了方便咱們進行一個網絡請求特地引用一個jQuery,你以爲合理嗎?jQuery的代碼1w+行,Vue的代碼才1w+行,徹底沒有必要爲了用網絡請求就引用這個重量級的框架。java

選擇三:官方在Vue1.x的時候,推出了Vue-resourcenode

Vue-resource的體積相對於jQuery小不少,另外Vue-resource是官方推出的。爲何不選擇它呢?在Vue2.0退出後,Vue做者就在GitHub的Issues中說明了去掉vue-resource,而且之後也不會再更新。那麼意味着之後vue-reource再也不支持新的版本也不會再繼續更新和維護,若是使用它對之後的項目開發和維護都存在很大的隱患。ios

選擇四: axiosajax

在說明再也不繼續更新和維護vue-resource的同時,做者還推薦了一個框架: axios。axios有很是多的優勢而且用起來也很是方便,咱們將對他詳細學習。npm

2. jsonp網絡請求封裝

在前端開發中咱們一種常見的網絡請求方式就是JSONP,使用JSONP最主要的緣由每每是爲了解決跨域訪問的問題。json

JSONP的原理是什麼呢?JSONP的核心在於經過<script>標籤的src來幫助咱們請求數據,緣由是咱們的項目部署在domain1.com服務器上時,是不能直接訪問domain2.com服務器上的資料的。這個時候咱們利用<script>標籤的src幫助咱們去服務器請求到數據,將數據當作一個javascript的函數來執行而且執行的過程當中傳入咱們須要的json。因此封裝jsonp的核心就在於咱們監聽window上的jsonp進行回調時的名稱。

JSONP如何封裝呢?咱們一塊兒本身來封裝一個處理JSONP的代碼吧

function jsonp(options) {
    options = options || {};
    if (!options.url || !options.callback) {
        throw new Error('請傳入合法參數');
    }

    // 建立script標籤,並加入到頁面中
    // 返回的回調函數名,加入隨機參數避免緩存
    var callbackName = ('jsonp_' + Math.random()).replace('.', '');
    // 獲取head標籤
    var head = document.getElementsByTagName('head')[0];
    // 填充回調函數名
    options.data[options.callback] = callbackName;
    // 格式化參數
    var paramas = formatParams(options.data);
    // 建立script標籤
    var script = document.createElement('script');
    // 插入script標籤的head
    head.appendChild(script);

    // 建立JSONP回調函數
    // window[callbackName]的形式,但是的回調函數可被全局調用
    window[callbackName] = function(json) {
        // script標籤的哦src屬性只在第一次設置時起做用,即script標籤標籤是沒法重用的,故每次建立回調函數,即每次設置script標籤是須要將前一個script以及其src移除
        head.removeChild(script);
        clearTimeout(script.timer);
        window[callbackName] = null;
        options.success && options.success(json);
    };

    // 發送請求

    script.src = options.url + '?' + paramas;
    // 超時處理
    if (options.timeout) {
        script.timer = setTimeout(function() {
            window[callbackName] = null;
            head.removeChild(script);
            options.fail && options.fail(message, '請求超時');
        }, timeout);
    }
}

//格式化參數
function formatParams(data) {
    var arr = [];
    for (var name in data) {
        arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[i]));
    }
    return arr.join('&');
}

3. axios基本使用

3.1 爲何選擇axios(ajax i/o system)

爲何選擇axios? 做者推薦,功能特色

功能特色

  • 在瀏覽器中發送 XML.HttpRequests 請求
  • 在 node.js 中發送 http請求
  • 支持 Promise API
  • 攔截請求和響應
  • 轉換請求和響應數據
  • ...
3.2 請求方式

支持多種請求方式

  • axios(config)
  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.head(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])
  • axios.patch(url[, data[, config]])
3.3 發送基本請求

安裝axios

npm install axios --save

前端配置跨域

//vue.comfig.js
module.exports = {
    devServer: {
        //配置跨域
        proxy: {  
            '/api': {  ///配置跨域,將全部帶有'/api'的請求都攔截,代理到target上
                target: 'http://mpolaris.top:8080', //目標ip地址
                ws: true,
                changOrigin: true,//容許跨域
                pathRewrite: {
                    '^/api': ''// 替換請求路徑中的'/api'字符
                }
            }
        }
    }
}

發送get請求

<script>
import axios from 'axios'

export default {
  name: 'app',
  created() {
    //1.沒有請求參數
    axios.get('/api/portal/article/categories')
    .then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    })
    //2.有請求參數
    axios.get('/api/portal/article/label/',{
      params: {size: 3}
    }).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    })
  }
}
</script>

發送並行請求

有時候,咱們可能需求同時發送兩個請求,使用axios.all, 能夠放入多個請求的數組,axios.all([]) 返回的結果是一個數組,使用 axios.spread 可將數組 [res1,res2] 展開爲 res1, res2

<script>
import axios from "axios";

export default {
  name: "app",
  created() {
    //發送並行請求
    axios
      .all([
        axios.get("/api/portal/article/categories"),
        axios.get("/api/portal/article/label/", {
          params: { size: 3 },
        }),
      ])
      .then(
        axios.spread((res1, res2) => {
          console.log(res1);
          console.log(res2);
        })
      );
  }
};
</script>
3.4 全局配置

在上面的示例中咱們的 BaseURL 是固定的,事實上在開發中可能不少參數都是固定的,這個時候咱們能夠進行一些抽取,也能夠利用axiox的全局配置屬性 defaults

export default {
  name: "app",
  created() {
    //提取全局的配置
    axios.defaults.baseURL = '/api';
	axios.defaults.timeout = 5000;
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    //...
      
    axios
      .all([
        axios.get("/portal/article/categories"),
        axios.get("/portal/article/label/", {
          params: { size: 3 },
        }),
      ])
      .then(
        axios.spread((res1, res2) => {
          console.log(res1);
          console.log(res2);
        })
      );
  }
};
</script>
3.5 axios常見的配置項

請求地址

  • url: '/user'

請求類型

  • method: 'get'

根路徑

請求前的數據處理

  • transformRequest: [function(data){}]

請求後的數據處理

  • transformResponse: [function(data){}]

自定義的請求頭

  • headers: {'x-Requested-With': 'XMLHttpRequest'}

URL查詢對象

  • params: { id: 12 }

查詢對象序列化函數

  • paramsSerializer: function(params){ }

request body

  • data: { key: 'aa'}

超時設置

  • timeout: 1000,

跨域是否帶Token

  • withCredentials: false

自定義請求處理

  • adapter: function(resolve, reject, config){}

身份驗證信息

  • auth: { uname: '', pwd: '12'}

響應的數據格式 json / blob /document /arraybuffer / text / stream

  • responseType: 'json'

4. axios的實例和模塊封裝

4.1 axios實例

爲何要建立axios的實例呢?

當咱們從axios模塊中導入對象時,使用的實例是默認的實例(全局axios)。當給該實例設置一些默認配置時這些配置就被固定下來了,可是後續開發中某些配置可能會不太同樣。好比某些請求須要使用特定的baseURL或者timeout或者content-Type等,這個時候咱們就能夠建立新的實例而且傳入屬於該實例的配置信息。

//建立新的實例
const axiosInstance = axios.create({
   baseURL: '/api',
   timeout: 2000,
   headers: {
     'Content-Type': 'application/x-www-form-urlencoded'
   }
});
//發送網絡請求
axiosInstance({
   url: '/portal/article/categories',
   method: 'get'
}).then(res => {
   console.log(res);
})
4.2 axios模塊封裝
//utils/httpRequest.js

import axios from 'axios'

//1.初步封裝,將結果或錯誤信息經過函數形參回調出去
// export function request(config,success,failure) {
//     //建立axios實例
//     const instance = axios.create({
//         baseURL: '/api',
//         timeout: 5000
//     });

//     instance(config).then(res => {
//         success(res);
//     }).catch(err => {
//         failure(err);
//     })
// }


// 2.改進:使用Promise封裝
// export function request (config) {
//     return new Promise((resolve, reject) => {
//         //建立axios實例
//         const instance = axios.create({
//             baseURL: '/api',
//             timeout: 5000
//         });

//         //發送網絡請求
//         instance(config).then(res => {
//             resolve(res);
//         }).catch(err => {
//             reject(err);
//         })
//     })
// }

// 3.改進:其實axios實例返回的就是一個Promise(看源碼發現),因此
//      咱們能夠直接返回axios實例,在外面也能夠直接調then和catch
export function request(config) {
    //建立axios實例
    const instance = axios.create({
        baseURL: '/api',
        timeout: 5000
    });

    //發送網絡請求
    return instance(config);
}
<script>
import { request } from "@/utils/httpRequest";

export default {
  name: "app",
  created() {
    // request(
    //   {
    //     url: "/portal/article/categories",
    //     method: "get",
    //   },res => {
    //     console.log(res);
    //   }, err => {
    //     console.log(err);
    //   }
    // );

    request({
      url: '/portal/article/categories',
      method: 'get'
    }).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);

    })
  },
};
</script>
4.3 攔截器

axios提供了攔截器,用於咱們在發送每次請求或者獲得相應後進行對應的處理。

給咱們上面封裝的請求加上攔截器

//utils/httpRequest.js

import axios from 'axios'

export function request(config) {
    //建立axios實例
    const instance = axios.create({
        baseURL: '/api',
        timeout: 5000
    });

    //配置請求和響應攔截,注意直接寫axios就是全局攔截
    instance.interceptors.request.use(config => {
        console.log('這裏是request攔截success中');
        return config
    }, err => {
        console.log('這裏是request攔截器failure中');
        return err
    })

    instance.interceptors.response.use(response => {
        console.log('這裏是response攔截success中');
        return response.data
    }, err => {
        console.log('這裏是response攔截器failure中');
        return err
    })

    //發送網絡請求
    return instance(config);
}
相關文章
相關標籤/搜索