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
在前端開發中咱們一種常見的網絡請求方式就是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('&'); }
爲何選擇axios? 做者推薦,功能特色
功能特色
XML.HttpRequests
請求http
請求Promise API
支持多種請求方式
安裝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>
在上面的示例中咱們的 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>
請求地址
請求類型
根路徑
請求前的數據處理
請求後的數據處理
自定義的請求頭
URL查詢對象
查詢對象序列化函數
request body
超時設置
跨域是否帶Token
自定義請求處理
身份驗證信息
響應的數據格式 json / blob /document /arraybuffer / text / stream
爲何要建立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); })
//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>
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); }