學(xué)習(xí) axios 的基本使用和項目級封裝

一、Ajax

在很久以前項目中進行數(shù)據(jù)處理通常是發(fā)送 Ajax(Asynchronous JavaScript and XML)吝沫,以前使用原生的 XMLHTTPRequest。

其中傳統(tǒng)的 Web 應(yīng)用允許用戶端填寫表單(form),當(dāng)提交表單時就向網(wǎng)頁服務(wù)器發(fā)送一個請求。服務(wù)器接收并處理傳來的表單,然后送回一個新的網(wǎng)頁蛛壳,但這個做法浪費了許多帶寬杏瞻,因為在前后兩個頁面中的大部分HTML碼往往是相同的。最重要的是網(wǎng)頁會跳轉(zhuǎn)衙荐,頁面的重新刷新捞挥。

XMLHttpRequest 是一個API,微軟發(fā)明,但是早期一直沒有標(biāo)準(zhǔn)化忧吟,每家瀏覽器的實現(xiàn)或多或少有點不同砌函。2008年2月,就提出了XMLHttpRequest Level 2 草案溜族。

它請求數(shù)據(jù)不會使整個頁面刷新讹俊。這使得網(wǎng)頁只更新一部分頁面而不會打擾到用戶。而且 XMLHttpRequest 可以取回所有類型的數(shù)據(jù)資源煌抒,并不局限于XML仍劈。 而且除了HTTP ,它還支持fileftp 協(xié)議。

老的模板如下:

var xhr = new XMLHttpRequest(); // 創(chuàng)建xhr對象
xhr.open( method, url ,true);
xhr.onreadystatechange = function () { ... };
xhr.setRequestHeader( ..., ... );
xhr.send( optionalEncodedData );

新的模板如下

 let xhr = new XMLHttpRequest();
// 請求成功回調(diào)函數(shù)
xhr.onload = e => {
    console.log('request success');
};
// 請求結(jié)束
xhr.onloadend = e => {
    console.log('request loadend');
};
// 請求出錯
xhr.onerror = e => {
    console.log('request error');
};
// 請求超時
xhr.ontimeout = e => {
    console.log('request timeout');
};
//進度信息寡壮,分成上傳和下載兩種情況贩疙。下載的progress事件屬于XMLHttpRequest對象,上傳的progress事件屬于XMLHttpRequest.upload對象况既。
xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;
function updateProgress(event) {
    if (event.lengthComputable) {
        //lengthComputable:返回一個布爾值这溅,表示當(dāng)前進度是否具有可計算的長度。如果為false棒仍,event.total=0悲靴。
        let percentComplete = event.loaded / event.total; 
        //event.total是需要傳輸?shù)目傋止?jié),event.loaded是已經(jīng)傳輸?shù)淖止?jié)莫其。
    } 
}
與progress事件相關(guān)的对竣,還有其他五個事件庇楞,可以分別指定回調(diào)函數(shù):

  * load事件:傳輸成功完成。

  * abort事件:傳輸被用戶取消否纬。

  * error事件:傳輸中出現(xiàn)錯誤吕晌。

  * loadstart事件:傳輸開始。

  * loadEnd事件:傳輸結(jié)束临燃,但是不知道成功還是失敗睛驳。
// 請求回調(diào)函數(shù).XMLHttpRequest標(biāo)準(zhǔn)又分為Level 1和Level 2,這是Level 1和的回調(diào)處理方式
// xhr.onreadystatechange = () => {
//  if (xhr.readyState !== 4) {
//  return;
//  }
//  const status = xhr.status;
//  if ((status >= 200 && status < 300) || status === 304) {
//  console.log(xhr.responseText);
//  } else {
//  console.log(xhr.statusText);
//  }
//  };

xhr.timeout = 0; // 設(shè)置超時時間,0表示永不超時
// 初始化請求
xhr.open('GET/POST/DELETE/...', '/url', true || false);
// 設(shè)置期望的返回數(shù)據(jù)類型 'json' 'text' 'document' ...
xhr.responseType = '';
// 設(shè)置請求頭
xhr.setRequestHeader('', '');
// 發(fā)送請求
xhr.send(null || new FormData || 'a=1&b=2' || 'json字符串');

http2 去參考
阮一峰 - XMLHttpRequest Level 2 使用指南
你不知道的 XMLHttpRequest

Jquery的Ajax

這個就很熟了吧,放個模板:

$.ajax({
   type: 'POST',
   url: url,
   data: data,
   dataType: dataType,
   success: function () {},
   error: function () {}
});

JQuery 對其 XMLHTTPRequest 進行了封裝膜廊,還增添了對 JSONP 的支持乏沸。

ES6 的fetch

fetch是基于Promise設(shè)計的號稱是 AJAX 的替代品,它的好處在《傳統(tǒng) Ajax 已死爪瓜,F(xiàn)etch 永生》中提到的有:

語法簡單蹬跃,更加語義化
基于標(biāo)準(zhǔn)的Promise實現(xiàn),支持async/await
脫離了XHR铆铆,是ES規(guī)范里新的實現(xiàn)方式
但是 fetch 缺點也很明顯:

  1. fetch只對網(wǎng)絡(luò)請求報錯蝶缀,沒有狀態(tài)碼,需要自己封裝
  2. fetch默認不會帶cookie薄货,需要添加配置項
  3. fetch不支持abort翁都,不支持超時控制,使用setTimeout及Promise.reject的實現(xiàn)的超時控制并不能阻止請求過程繼續(xù)在后臺運行谅猾,造成了流量的浪費
  4. fetch沒有辦法原生監(jiān)測請求的進度柄慰,而XHR可以
  5. fetch不支持超時timeout處理
  6. fetch不支持JSONP

深入可參考:《fetch沒有你想象的那么美》《fetch使用的常見問題及解決方法

現(xiàn)在的王者 axios

fetch 太新還需要完善,JQuery 已經(jīng)遲暮税娜,現(xiàn)在的王者當(dāng)然屬于 axios 了坐搔。axios 作為 Ajax 的替代品,底層是原生的 Ajax敬矩,沒有使用 fetch薯蝎,但是封裝的和內(nèi)置fetch 一樣好用。它有很多優(yōu)秀的特性谤绳,例如攔截請求和響應(yīng)占锯、取消請求、轉(zhuǎn)換json缩筛、客戶端防御XSRF等消略。所以我們的尤大大也是果斷放棄了對其官方庫vue-resource的維護,直接推薦我們使用axios庫瞎抛。如果還對axios不了解的艺演,可以移步axios文檔

一、axios 一些配置
  • 全局默認配置
    當(dāng)我們使用 axios 的時候胎撤,可以使用以下代碼進行 axios 默認配置晓殊。
import axios from "axios";
axios.defaults.baseURL = 'http://127.0.0.1:8080/api/';//每條axios請求都會加上這個基準(zhǔn)網(wǎng)址
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
  • 實例化配置
import axios from "axios";

const http = axios.create({
    baseURL : 'http://127.0.0.1:8080/api/',
    timeout : 1000 
});

export default http;

實例化配置詳解axios.create({})里面的配置對象提取出來為 config:

import axios from "axios";
const config = {
    // `url` 是用于請求的服務(wù)器 URL
    //如axios.get(url,config);這里的url會覆蓋掉config中的url
    url: '/',

    // `method` 是請求時的方法
    method: 'get', // 默認是 get

    // `baseURL` 將自動加在 `url` 前面,除非 `url` 是一個絕對 URL伤提。
    baseURL: 'api/',

    // `transformRequest` 允許在向服務(wù)器發(fā)送前巫俺,修改請求數(shù)據(jù),即要傳遞的data數(shù)據(jù)
    // 只能用在 'PUT', 'POST' 和 'PATCH' 這幾個請求方法
    // 后面數(shù)組中的函數(shù)必須返回一個字符串肿男,或 ArrayBuffer介汹,或 Stream
    transformRequest: [function (data) {
        // 對 data 進行任意轉(zhuǎn)換處理
        data = JSON.stringify(data);
        //當(dāng)我們發(fā)送POST請求的時候,如果打開這個函數(shù)舶沛,后臺會得到的結(jié)果[Object,Object]
        //要么不打開要么變成字符串
        return data;
    }],

    // `transformResponse` 在傳遞給 then/catch 前嘹承,允許修改響應(yīng)數(shù)據(jù)
    //不分請求方式
    transformResponse: [function (data) {
        // 對 data 進行任意轉(zhuǎn)換處理
        return data;
    }],

    // `headers` 是即將被發(fā)送的自定義請求頭
    //NodeJs通過req.headers['x-requested-with']能得到XMLHttpRequest
    //用來判斷是同步提交還是異步提交
    //"content-Type":"application/x-www-form-urlencoded"請求頭
    headers: {
        'X-Requested-With': 'XMLHttpRequest',
        //'Content-Type': 'application/x-www-form-urlencoded',
        //'Token': '',
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
    },

    // `params` 是即將與請求一起發(fā)送的 URL 參數(shù)
    // 必須是一個無格式對象(plain object)或 URLSearchParams 對象
    params: {

    },

    //沒明白這個配置
    // `paramsSerializer` 是一個負責(zé) `params` 序列化的函數(shù)
    // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
    // paramsSerializer: function(params) {
    //  // return Qs.stringify(params, {arrayFormat: 'brackets'})
    // },

    // `data` 是作為請求主體被發(fā)送的數(shù)據(jù)
    // 只適用于這些請求方法 'PUT', 'POST', 和 'PATCH'
    // 在沒有設(shè)置 `transformRequest` 時,必須是以下類型之一:
    // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
    // - 瀏覽器專屬:FormData, File, Blob
    // - Node 專屬: Stream
    data: {

    },

    // `timeout` 指定請求超時的毫秒數(shù)(0 表示無超時時間)
    // 如果請求響應(yīng)時間超過 `timeout` 的時間如庭,請求將被中斷
    timeout: 3000,

    // `withCredentials` 表示跨域是否攜帶cookie叹卷,三步設(shè)置才能生效
    withCredentials: false, // 默認的

    //沒明白
    // `adapter` 允許自定義處理請求,以使測試更輕松
    // 返回一個 promise 并應(yīng)用一個有效的響應(yīng) (查閱 [response docs](#response-api)).
    // adapter: function (config) {
    //   /* ... */
    // },

    // `auth` 表示應(yīng)該使用 HTTP 基礎(chǔ)驗證坪它,并提供憑據(jù)
    // 這將設(shè)置一個 `Authorization` 頭骤竹,覆寫掉現(xiàn)有的任意使用 `headers` 設(shè)置的自定義 `Authorization`頭
    //NodeJs 通過req.headers.authorization可以得到
    //這個和token登錄不一樣
    auth: {
        username: 'Condor Hero',
        password: 'password'
    },

    // `responseType` 表示服務(wù)器響應(yīng)的數(shù)據(jù)類型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
    responseType: 'json', // 默認的

    // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名稱
    // xsrfCookieName: 'XSRF-TOKEN', // default

    // `xsrfHeaderName` 是承載 xsrf token 的值的 HTTP 頭的名稱
    // xsrfHeaderName: 'X-XSRF-TOKEN', // 默認的

    // `onUploadProgress` 允許為上傳處理進度事件
    // onUploadProgress: function (progressEvent) {
    //   // 對原生進度事件的處理
    // },

    // `onDownloadProgress` 允許為下載處理進度事件
    // onDownloadProgress: function (progressEvent) {
    //   // 對原生進度事件的處理
    // },

    // `maxContentLength` 定義允許的響應(yīng)內(nèi)容的最大尺寸
    // maxContentLength: 2000,

    // `validateStatus` 定義對于給定的HTTP 響應(yīng)狀態(tài)碼是 resolve 或 reject  promise 哟楷。如果 `validateStatus` 返回 `true` (或者設(shè)置為 `null` 或 `undefined`),promise 將被 resolve; 否則否灾,promise 將被 rejecte
    // validateStatus: function (status) {
    //   return status >= 200 && status < 300; // 默認的
    // },

    // `maxRedirects` 定義在 node.js 中 follow 的最大重定向數(shù)目
    // 如果設(shè)置為0卖擅,將不會 follow 任何重定向
    maxRedirects: 5, // 默認的

  // `httpAgent` 和 `httpsAgent` 分別在 node.js 中用于定義在執(zhí)行 http 和 https 時使用的自定義代理。允許像這樣配置選項:
  // `keepAlive` 默認沒有啟用
  // httpAgent: new http.Agent({ keepAlive: true }),
  // httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy' 定義代理服務(wù)器的主機名稱和端口
  // `auth` 表示 HTTP 基礎(chǔ)驗證應(yīng)當(dāng)用于連接代理墨技,并提供憑據(jù)
  // 這將會設(shè)置一個 `Proxy-Authorization` 頭惩阶,覆寫掉已有的通過使用 `header` 設(shè)置的自定義 `Proxy-Authorization` 頭。
  // proxy: {
  //   host: '127.0.0.1',
  //   port: 9000,
  //   auth: {
  //     username: 'mikeymike',
  //     password: 'rapunz3l'
  //   }
  // },

  // `cancelToken` 指定用于取消請求的 cancel token
  // (查看后面的 Cancellation 這節(jié)了解更多)
  // cancelToken: new CancelToken(function (cancel) {})
}



// 創(chuàng)建實例時設(shè)置配置的默認值
const http = axios.create(config);

// 添加請求攔截器
http.interceptors.request.use(config => {
    // 在發(fā)送請求之前做些什么
    return config;
}, function (error) {
    // 對請求錯誤做些什么
    return Promise.reject(error);
});

// 添加響應(yīng)攔截器data.data
http.interceptors.response.use(function (response) {
    // 對響應(yīng)數(shù)據(jù)做點什么response.status
    return response;
}, function (error) {
    // 對響應(yīng)錯誤做點什么error.response.status
    return Promise.reject(error);
});


export default http;

注釋掉的都是不太懂的扣汪,除了上傳下載断楷。。崭别。
幾點說明:

  1. 請求頭 content-type 不寫默認使用 json 冬筒,請求的格式 payload ,也可以定義為下面的這種格式茅主。
headers: {'X-Requested-With': 'XMLHttpRequest',"content-Type":"application/x-www-form-urlencoded"},
content-type:application/json

content-Type":"application/x-www-form-urlencoded
  1. 某個請求的響應(yīng)包含以下信息:
{
  // `data` 由服務(wù)器提供的響應(yīng)
  data: {},

  // `status` 來自服務(wù)器響應(yīng)的 HTTP 狀態(tài)碼
  status: 200,

  // `statusText` 來自服務(wù)器響應(yīng)的 HTTP 狀態(tài)信息
  statusText: 'OK',

  // `headers` 服務(wù)器響應(yīng)的頭
  headers: {},

   // `config` 是為請求提供的配置信息
  config: {},
 // 'request'
  // `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance the browser
  request: {}
}
圖證
  1. 并行請求
const getUserAccount = ()=>{
    return axios.get("/list");
}

const getUserPermissions =  ()=> {
    return axios.post("post",{name:"Condor Hero"});
}
axios.all([getUserAccount(),getUserPermissions()]).then(axios.spread(function (acct, perms) {
    // 兩個請求現(xiàn)在都執(zhí)行完成
    console.log(acct,perms)
}));
  • 自定義配置
axios.get(url,{
    timeout: 5000
})

如果同時在三個配置設(shè)置里面 timeout 那他們的優(yōu)先級如下:

默認 < 實例 < 自定義

二舞痰、攔截器 Interceptors

在每次發(fā)請求之前,都會執(zhí)行的函數(shù)诀姚,就是 axios 攔截器响牛。通常用途:

  • 判斷是否登錄。
  • 制作 loading 動畫、當(dāng)超時呀打、錯誤的時候集中處理錯誤樣式矢赁。
  • 結(jié)合接口清單,判斷接口是模擬還是真實贬丛。

示例模板:

import axios from "axios";

const http = axios.create({
    baseURL : 'http://127.0.0.1:8080/api/',
    timeout : 1000 
});
// Add a request interceptor每次請求之前會經(jīng)過這里
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    // ①這里可以發(fā)送Ajax
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });
 
// Add a response interceptor每次請求響應(yīng)之后會經(jīng)過這里
axios.interceptors.response.use(function (response) {
    // Do something with response data
    // 這里可根據(jù)①請求返回的結(jié)果進行權(quán)限判定非法登錄等操作
    return response;
  }, function (error) {
    // Do something with response error
    //響應(yīng)錯誤可在此操作返回模擬數(shù)據(jù)接口
    return Promise.reject(error);
  });
export default http;
三撩银、封裝 axios 1.0 版本

一般我們封裝的 Ajax 都會單獨放在一個文件,常見的叫法就是 http 瘫寝,API蜒蕾,Ajax,server焕阿,request等等咪啡。

auth.js 這個文件是用來處理 token 的。關(guān)于 token 存儲地方一般來講我們是存儲到 sessionStorage 里面暮屡,如果前端登錄功能要做一個記住密碼的功能撤摸,那我們能選擇的就是存儲到 localStorage 里面或者是存在 cookie 里面。cookie 默認是臨時存儲的褒纲,當(dāng)瀏覽器關(guān)閉進程的時候自動銷毀准夷,每個不能超過 4KB,要想長時間保存一個cookie莺掠,就需要設(shè)置cookie的過期時間衫嵌。

關(guān)于登錄時是使用 token 還是 cookie 進行身份驗證,如果使用 token 彻秆,token 是放在 URL 里面還是請求頭 head 里面楔绞,請看:

Session與Token認證機制 前后端分離下如何登錄

下面是 cookie 最常見的應(yīng)用場景了

保存用戶登錄信息。這應(yīng)該是最常用的了唇兑。當(dāng)您訪問一個需要登錄的界面酒朵,例如微博、百度及一些論壇扎附,在登錄過后一般都會有類似"下次自動登錄"的選項蔫耽,勾選過后下次就不需要重復(fù)驗證。這種就可以通過cookie保存用戶的id留夜。
創(chuàng)建購物車匙铡。購物網(wǎng)站通常把已選物品保存在cookie中,這樣可以實現(xiàn)不同頁面之間數(shù)據(jù)的同步(同一個域名下是可以共享cookie的)碍粥,同時在提交訂單的時候又會把這些cookie傳到后臺慰枕。
跟蹤用戶行為。例如百度聯(lián)盟會通過cookie記錄用戶的偏好信息即纲,然后向用戶推薦個性化推廣信息具帮,所以瀏覽其他網(wǎng)頁的時候經(jīng)常會發(fā)現(xiàn)旁邊的小廣告都是自己最近百度搜過的東西。這是可以禁用的,這也是cookie的缺點之一蜂厅。

在 cookie 里寫入匪凡、讀取、刪除掘猿,使用的是 js-cookie病游,下載量還是不少滴:


2019年12月7日22:00:10

使用方法也是很簡單的,cookie 的 讀稠通、寫衬衬、刪。

import Cookies from 'js-cookie'

const TokenKey = 'X_Token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

js-cookie 的原理就是使用 document.cookie 這個 API改橘,詳細原碼去參考 js-cookie源碼學(xué)習(xí)滋尉,我是不同意用 js-cookie 去存儲token的,因為每次http請求都會攜帶cookie里面的數(shù)據(jù)飞主,最好使用 HTML5 中的 sessionStorage 或 localStorage狮惜。但是如果項目瀏覽器不支持 H5 那 token 就只能存儲在 cookie 里面了。

request.js 的內(nèi)容:

import axios from 'axios';
import {
  MessageBox,
  Message
} from 'element-ui'
import store from '@/store'
import {
  getToken,
  removeToken
} from '@/utils/auth'

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  withCredentials: true, // send cookies when cross-domain requests
  timeout: 50000 // request timeout
})

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent
    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      config.headers['X-Token'] = getToken()
    }
    // 設(shè)置請求時間碌识,為登錄超時
    localStorage.setItem('lastRequestTime', new Date().getTime());
    return config
  },
  error => {
    // do something with request error
    // for debug
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  res => {
    if (res.status == 200) {
      if(res.data.status == 401) {
        // 清空token
        removeToken();
        // to re-login
        MessageBox.confirm('登錄超時,您可以選擇留在本頁面或者重新登錄', '登錄超時', {
          confirmButtonText: '重新登錄',
          cancelButtonText: '留在本頁',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload() // 為了重新實例化vue-router對象 避免bug
          })
        });
        return Promise.reject({message: '登陸超時'});
      } else {
        return res;
      }
    } else {
      Message({
        message: '網(wǎng)絡(luò)異常', // error.message
        type: 'error',
        duration: 5 * 1000
      })
      return Promise.reject(error)
    }
  },
  error => {
    Message({
      message: '請求服務(wù)異常', // error.message
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

上面 axios 實例化的時候有一個字段為:withCredentials:true 這表示什么來?

// withCredentials indicates whether or not cross-site Access-Control requests
// should be made using credentials
withCredentials: false, // default

官網(wǎng)介紹是跨域請求應(yīng)該使用的憑證碾篡,翻譯過來就是跨域帶上cookies。同時后臺需要配合設(shè)置 Access-Control-Allow-Origin 為你的源地址筏餐,例如 http://localhost:8080开泽,而不能是 *,且還要設(shè)置 header('Access-Control-Allow-Credentials: true');

上面 axios 是實例化直接暴露出來的魁瞪,都沒有對它的方法 get穆律,put等進行封裝,可能很多人會按如下的代碼進行 axios 方法的封裝:

export function get(url, params = {}){    
    return new Promise((resolve, reject) =>{        
        axios.get(url, {            
            params: params        
        })        
        .then(res => {            
            resolve(res.data);        
        })        
        .catch(err => {            
            reject(err.data)        
        })    
    });
}

這樣寫的好處之一就是可以在全局直接引入

import Vue from 'vue'
import { post, get, patch, put, del } from './index'
Vue.prototype.$post = post

而不用每次在組件內(nèi)部都引入佩番。但是直接暴露 axios 的好處自定義化更高众旗“丈迹看個人習(xí)慣這點趟畏。

API 管理我們也會單獨放在一個文件里面,例如涉及用戶登錄注冊的這塊全部放在 user.js 文件里面:

import request from '@/utils/request'

export function login(data) {
  return request({
    url: '/m/crops/admin/sys/login',
    method: 'post',
    data
  })
}

export function logout(data) {
  return request({
    url: '/m/crops/admin/sys/logout',
    method: 'post',
    data: data
  })
}
export function changePassword(data) {
  return request({
    url: '/m/crops/admin/sys/login',
    method: 'post',
    data
  })
}

export function changeInformation(data) {
  return request({
    url: '/m/crops/admin/sys/user/updateSysUserPassword',
    method: 'post',
    data: data
  })
}

export function updateSysUser(data) {
  return request({
    url: '/m/crops/admin/sys/user/updatePictureAndRealName',
    method: 'post',
    data: data
  })
}

當(dāng)我們需要使用的時候只需要:

import {
    addServiceStation
} from "@/api/mapOn/index.js";
addServiceStation(this.addForm).then(res => {
    if (res.data.status === 200) {
        this.$Notice.success({
            title: "更新成功",
            desc: ""
        });
        this.$router.push({
            name: "stationmanagement"
        });
    } else {
        this.$Notice.warning({
            title: "數(shù)據(jù)有誤",
            desc: res.data.message
        });
    }
});
登錄過期
mounted() {
    let self = this;
    let loginTimeOut = self.$store.state.settings.loginTimeOut;//12 * 60 *1000
    let lastTime = localStorage.getItem('lastRequestTime');
    let currentTime;
    let interval;

    function checkTimeout() {
        currentTime = new Date().getTime();
        if (currentTime - lastTime  > loginTimeOut && getToken()) {
            // 清理定時器
            clearInterval(interval);
            // 清理token
            removeToken();
            self.$alert('您的登錄信息已過期滩租,請重新登錄...', '登錄超時', {
                confirmButtonText: '重新登錄',
                type: 'warning'
            }).then(() => {
                self.$store.dispatch('user/resetToken').then(() => {
                    location.reload() // 為了重新實例化vue-router對象 避免bug
                })
            });
        }
    }

    interval = window.setInterval(checkTimeout, 1000);
}

另外一種方法去參考:vue中Axios的封裝和API接口的管理
文章作者最后修改的版本挺適合大型項目多人開發(fā):
base.js 文件:定義 baseURL

/**
 * 接口域名的管理
 */
const base = {    
    sq: 'https://xxxx111111.com/api/v1',    
    bd: 'http://xxxxx22222.com/api'
}

export default base;

article.js:每個人負責(zé)的模塊赋秀,例如你負責(zé)article模塊

/**
 * article模塊接口列表
 */

import base from './base'; // 導(dǎo)入接口域名列表
import axios from '@/utils/http'; // 導(dǎo)入http中創(chuàng)建的axios實例
import qs from 'qs'; // 根據(jù)需求是否導(dǎo)入qs模塊

const article = {    
    // 新聞列表    
    articleList () {        
        return axios.get(`${base.sq}/topics`);    
    },    
    // 新聞詳情,演示    
    articleDetail (id, params) {        
        return axios.get(`${base.sq}/topic/${id}`, {            
            params: params        
        });    
    },
    // post提交    
    login (params) {        
        return axios.post(`${base.sq}/accesstoken`, qs.stringify(params));    
    }
    // 其他接口…………
}

export default article;

api.js :把所有的模塊進行合并整理

/** 
 * api接口的統(tǒng)一出口
 */
// 文章模塊接口
import article from '@/api/article';
// 其他模塊的接口……

// 導(dǎo)出接口
export default {    
    article,
    // ……
}

最后,為了方便內(nèi)部組件的調(diào)用律想,我們需要將其掛載到 vue 的原型上猎莲。在main.js中:

import Vue from 'vue'
import App from './App'
import router from './router' // 導(dǎo)入路由文件
import store from './store' // 導(dǎo)入vuex文件
import api from './api' // 導(dǎo)入api接口

Vue.prototype.$api = api; // 將api掛載到vue的原型上

然后我們可以在頁面中這樣調(diào)用接口,eg:

methods: {    
    onLoad(id) {      
        this.$api.article.articleDetail(id, {        
            api: 123      
        }).then(res=> {
            // 執(zhí)行某些操作      
        })    
    }  
}

最后還值得借鑒的是對狀態(tài)碼錯誤的處理技即,常見錯誤更加詳細的告訴用戶:

// 狀態(tài)碼判斷
switch (status) {
    // 401: 未登錄狀態(tài)著洼,跳轉(zhuǎn)登錄頁
    case 401:
        toLogin();
        break;
    // 403 token過期
    // 清除token并跳轉(zhuǎn)登錄頁
    case 403:
        tip('登錄過期,請重新登錄');
        localStorage.removeItem('token');
        store.commit('loginSuccess', null);
        setTimeout(() => {
            toLogin();
        }, 1000);
        break;
    // 404請求不存在
    case 404:
        tip('請求的資源不存在'); 
        break;
    default:
        console.log(other);   
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市身笤,隨后出現(xiàn)的幾起案子豹悬,更是在濱河造成了極大的恐慌,老刑警劉巖液荸,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞻佛,死亡現(xiàn)場離奇詭異,居然都是意外死亡娇钱,警方通過查閱死者的電腦和手機伤柄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來文搂,“玉大人适刀,你說我怎么就攤上這事∠妇危” “怎么了蔗彤?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疯兼。 經(jīng)常有香客問我然遏,道長,這世上最難降的妖魔是什么吧彪? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任待侵,我火速辦了婚禮,結(jié)果婚禮上姨裸,老公的妹妹穿的比我還像新娘秧倾。我一直安慰自己,他們只是感情好傀缩,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布那先。 她就那樣靜靜地躺著,像睡著了一般赡艰。 火紅的嫁衣襯著肌膚如雪售淡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天慷垮,我揣著相機與錄音揖闸,去河邊找鬼。 笑死料身,一個胖子當(dāng)著我的面吹牛汤纸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芹血,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼贮泞,長吁一口氣:“原來是場噩夢啊……” “哼楞慈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起啃擦,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤抖部,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后议惰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慎颗,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年言询,在試婚紗的時候發(fā)現(xiàn)自己被綠了俯萎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡运杭,死狀恐怖夫啊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辆憔,我是刑警寧澤撇眯,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站虱咧,受9級特大地震影響熊榛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腕巡,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一玄坦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绘沉,春花似錦煎楣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至另玖,卻和暖如春困曙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背日矫。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工赂弓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绑榴,地道東北人哪轿。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像翔怎,于是被迫代替她去往敵國和親窃诉。 傳聞我的和親對象是個殘疾皇子杨耙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容