前端廢物的自救之路(1)實(shí)現(xiàn)axios攔截器:對(duì)Nuxt.js中的@nuxtjs/axios進(jìn)行封裝

前端廢物的自救之路(1)實(shí)現(xiàn)axios攔截器:對(duì)Nuxt.js中的@nuxtjs/axios進(jìn)行封裝

前言

手頭有一個(gè)去年五月寫的遺留項(xiàng)目辞色,以前使用的是Spring Boot+Thymeleaf+AmazeUI(前臺(tái))+X-admin(后臺(tái))蚊夫,由于用戶反映有許多需要改進(jìn)的地方(并且打開項(xiàng)目一看滥崩,那代碼我自己也看不懂了娇哆,而且以現(xiàn)在的視角看那些代碼真的是爛到極致),故進(jìn)行徹底重構(gòu)首懈。

由于前臺(tái)需要SEO华畏,并且考慮到上一版中使用AmazeUI+Thymeleaf開發(fā)的體驗(yàn)極為痛苦,且新的后端(Gin)的模板引擎十分惡心(可能有人不這么認(rèn)為跨嘉,反正我認(rèn)為Gin的模板語法比Thymeleaf惡心多了)川慌,于是前端選擇了Nuxt.js。并且偿荷,由于前臺(tái)對(duì)響應(yīng)式有需求窘游,而且客戶認(rèn)為Vuetify太花哨,iView基礎(chǔ)版的組件又不夠用跳纳,所以UI框架前后臺(tái)統(tǒng)一使用Ant Design Vue

注:后端使用的是Gin贪嫂,并且實(shí)現(xiàn)了DDDCQS寺庄。關(guān)于這個(gè)項(xiàng)目的后端我們過段時(shí)間再另行討論。但是為了解釋部分前端代碼力崇,這一系列文章中可能也會(huì)貼出一些后端代碼以供參考斗塘。其中前端代碼會(huì)給出具體的文件名和路徑,后端代碼會(huì)在代碼前標(biāo)識(shí)為“后端代碼”亮靴。

由于網(wǎng)絡(luò)上使用Nuxt.js+Ant Design Vue的文章實(shí)在是太少了馍盟,作為一個(gè)后端一天能寫600+行(以前用Java的時(shí)候一天最多甚至能寫1200+行),前端一天寫100行能工作的代碼就滿足了的前端廢物茧吊,為了讓以后再寫類似的項(xiàng)目的時(shí)候能不這么肉疼贞岭,于是決定記錄下本次開發(fā)的過程八毯,不為別的,就為自己以后再用NuxtAnt Design Vue的時(shí)候少掉幾根頭發(fā)瞄桨。

雖然這個(gè)項(xiàng)目不能開源话速,但是考慮到以后可能還會(huì)做類似的項(xiàng)目,并且類似的解決方案的Demo實(shí)在是太少了芯侥,所以在這個(gè)項(xiàng)目完結(jié)后我也會(huì)根據(jù)我的開發(fā)過程整理一個(gè)開源的種子項(xiàng)目發(fā)布在GitHub上以供參考和使用泊交。

為什么需要axios攔截器?

項(xiàng)目本身是前后端分離的柱查,鑒權(quán)使用的是JWT廓俭。由于后端是根據(jù)請(qǐng)求頭中的X-Token字段進(jìn)行鑒權(quán)的,所以需要在每個(gè)請(qǐng)求的請(qǐng)求中放入Token唉工。但是我們不可能在每個(gè)接口里都這么做白指,最佳的解決方案當(dāng)然是利用axios攔截器來完成這個(gè)工作。

另外酵紫,后端所有的響應(yīng)無論成功還是失敗都具有統(tǒng)一的格式:

后端代碼

// @Description 生成一個(gè)成功請(qǐng)求的標(biāo)準(zhǔn)響應(yīng)格式的JSON
// @param data interface{} 響應(yīng)中要攜帶的數(shù)據(jù)
// @return result 生成的JSON
func Success(data interface{}) (result gin.H) {
    result = gin.H{
        "code":    Ok,
        "message": "Success",
        "data":    data,
    }
    return
}

// @Description 生成一個(gè)失敗請(qǐng)求的標(biāo)準(zhǔn)響應(yīng)格式的JSON
// @param errorCode ErrorCode 錯(cuò)誤碼
// @param message string 要顯示給用戶的錯(cuò)誤信息
// @return result 生成的JSON
func Error(errorCode ErrorCode, message string) (result gin.H) {
    result = gin.H{
        "code":    errorCode,
        "message": message,
        "data":    nil,
    }
    return
}

我們也不可能在每個(gè)接口里都去解析這個(gè)格式告嘲,這樣不僅不優(yōu)雅還很容易出錯(cuò),這時(shí)候就需要axios攔截器對(duì)響應(yīng)做統(tǒng)一的處理了奖地。

封裝@nuxtjs/axios

由于Nuxt.js對(duì)axios做了封裝橄唬,所以使用起來與直接使用axios有一些不同,在實(shí)現(xiàn)axios攔截器時(shí)與直接使用axios也不太一樣参歹。

注:我在新建項(xiàng)目的時(shí)候就選擇了axios仰楚,所以我的項(xiàng)目創(chuàng)建出來是自帶@nuxtjs/axios這個(gè)依賴包的,如果沒有的話可以使用npm自行安裝犬庇。如果使用的是我這篇文章所講的方法僧界,安裝時(shí)要安裝的包是@nuxtjs/axios而不是axios

添加axios攔截器插件

與在Vue中配置axios攔截器不同臭挽,在Nuxt.js中配置axios攔截器使用的是Nuxt.js的插件機(jī)制捂襟。要配置axios攔截器,我們需要在@/plugins目錄下新建一個(gè)axios.js(名稱無所謂欢峰,只要是.js文件就可以了葬荷,但是該文件的名稱與配置文件中的名稱要對(duì)應(yīng))文件,在這個(gè)文件中進(jìn)行具體的配置:

由于前端才剛剛開始寫纽帖,所以這個(gè)文件的內(nèi)容非常不全面宠漩,僅供參考,以后如果添加了新的重要的邏輯懊直,會(huì)在后續(xù)文章中對(duì)這部分代碼進(jìn)行編輯扒吁。

@/plugins/axios.js

import { message } from 'ant-design-vue'

export default function ({ store, redirect, app: { $axios } }) {
  // 后端接口地址
  $axios.defaults.baseURL = 'http://127.0.0.1:19090/api/'

  // Request攔截器:設(shè)置Token
  $axios.onRequest((config) => {
    // TODO 使用Vuex存儲(chǔ)Token,并做持久化處理
    // config.headers.common['X-Token'] = store.state.token
  })
  // Error攔截器:出現(xiàn)錯(cuò)誤的時(shí)候被調(diào)用室囊,根據(jù)狀態(tài)碼做對(duì)應(yīng)判斷并顯示全局Message
  $axios.onError((error) => {
    const code = parseInt(error.response && error.response.status)
    switch (code) {
      // 未登錄
      case 401:
        redirect('/login')
        break
      default:
        break
    }
    // 使用Ant Design Vue的message模塊顯示異常信息
    message.error(error.response.data.message, 5)
  })
  // Response攔截器:對(duì)正常返回的數(shù)據(jù)進(jìn)行處理
  $axios.onResponse((response) => {
    return response.data
  })
}

$axios.onRequest雕崩、$axios.onResponse$axios.onErrorNuxt.js提供的方法魁索,類似于直接使用axios時(shí)的$axios.interceptors.response.use方法,可以在這些方法中完成對(duì)請(qǐng)求信息和響應(yīng)信息的判斷與處理晨逝。這些方法與直接使用axios最大的不同就是默認(rèn)情況下不必返回任何內(nèi)容(當(dāng)然蛾默,onResponse還是需要返回相應(yīng)數(shù)據(jù)response.data,也就是響應(yīng)體本身(JSON)捉貌,包括了messagecode——當(dāng)然如果不需要這兩部分的話也可以返回response.data.data)支鸡,例如onRequest方法不必返回config等。

下面貼出純凈版的代碼供大家使用:

@/plugins/axios.js

export default function ({ store, redirect, app: { $axios } }) {
  $axios.onRequest((config) => {
  })
  
  $axios.onError((error) => {
  })
  
  $axios.onResponse((response) => {
  })
}

使用Ant Design Vue顯示全局消息

由于我在初始化項(xiàng)目的時(shí)候UI框架選擇了Ant Design Vue趁窃,所以項(xiàng)目里直接就整合好了Ant Design Vue牧挣,需要的時(shí)候直接引入就可以了——但是目前項(xiàng)目中沒有配置按需引入,所以前端性能可能會(huì)不太好醒陆,最后會(huì)配置一下按需引入瀑构。如果沒有選擇的話,可以使用npm進(jìn)行安裝刨摩,再使用Nuxt插件進(jìn)行整合寺晌。

可以看到我的代碼中有這么一句:

// 使用Ant Design Vue的message模塊顯示異常信息
message.error(error.response.data.message, 5)

因?yàn)閷?duì)于錯(cuò)誤信息,個(gè)人認(rèn)為使用全局顯示的方法比組件內(nèi)單獨(dú)顯示更好澡刹,因?yàn)檫@樣可以更方便地做全局處理(當(dāng)然也有人不這么認(rèn)為呻征,那樣的話可以在組件內(nèi)單獨(dú)使用Alert組件),所以每當(dāng)請(qǐng)求出現(xiàn)錯(cuò)誤的時(shí)候罢浇,都需要全局顯示這樣一條錯(cuò)誤信息陆赋。與在組件內(nèi)顯示錯(cuò)誤信息使用this.$message.error等不同,Ant Design Vue也給出了全局顯示錯(cuò)誤信息的方法:

組件提供了一些靜態(tài)方法嚷闭,使用方式和參數(shù)如下:

  • message.success(content, [duration], onClose)
  • message.error(content, [duration], onClose)
  • message.info(content, [duration], onClose)
  • message.warning(content, [duration], onClose)
  • message.warn(content, [duration], onClose) // alias of warning
  • message.loading(content, [duration], onClose)

——Ant Design Vue官方文檔

記得使用之前先導(dǎo)入message模塊:

import { message } from 'ant-design-vue'

效果:

image

在Nuxt.js中配置插件

有了插件之后還需要在Nuxt的配置文件nuxt.config.js中進(jìn)行配置才能真正生效:

  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: [
    '@/plugins/antd-ui',
    '@/plugins/axios'
  ],

注意這里的文件名是剛剛在@/plugins目錄下新建.js文件時(shí)所使用的文件名攒岛。我的文件名是axios.js所以這里填寫@/plugins/axios,如果是axios-config.js就需要填寫@/plugins/axios-config胞锰,以此類推灾锯。

組件內(nèi)使用

一般方法

以登錄為例:

@/pages/login.vue

  methods: {
    login () {
      this.$refs.loginForm.validate((valid) => {
        if (valid) {
          this.$axios.post('/login', {
            username: this.form.username,
            password: this.form.password
          }).then((res) => {
            // TODO 登錄后的Token保存、跳轉(zhuǎn)等操作
            this.$message.success(res.data.username, 5)
          })
        } else {
          return false
        }
      })
    },
    reset () {
      this.$refs.loginForm.resetFields()
    }
  }

與沒有axios攔截器的方法完全相同胜蛉。

效果:

image

asyncData()方法

以獲取一個(gè)測試接口的信息為例挠进,后端提供了一個(gè)測試接口/api/admin/test,攜帶Token進(jìn)行請(qǐng)求的話會(huì)返回成功信息:

后端代碼

// TODO admin測試
adminGroup.GET("/test", func(c *gin.Context) {
        c.JSON(http.StatusOK, response.Success("/api/admin/test: Admin Test Succeeded!??"))
})

@/pages/admin目錄下新建一個(gè)測試用的頁面并在asyncData()方法中請(qǐng)求對(duì)應(yīng)數(shù)據(jù)(在請(qǐng)求之前需要設(shè)置一下Token誊册。這里因?yàn)槲疫€沒整合Vuex,直接寫死了暖璧,所以對(duì)應(yīng)的代碼沒什么參考價(jià)值案怯,下一篇文章中會(huì)講如何整合Vuex以及在請(qǐng)求頭中設(shè)置Token):

@/pages/admin/test.vue

<template>
  <div>
    {{ info }}
  </div>
</template>

<script>
export default {
  name: 'AdminTest',
  asyncData (context) {
    return context.$axios.get('/admin/test').then((res) => {
      return {
        info: res
      }
    })
  },
  data () {
    return {
      info: ''
    }
  }
}
</script>

效果:

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市澎办,隨后出現(xiàn)的幾起案子嘲碱,更是在濱河造成了極大的恐慌金砍,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麦锯,死亡現(xiàn)場離奇詭異恕稠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扶欣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門鹅巍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人料祠,你說我怎么就攤上這事骆捧。” “怎么了髓绽?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵敛苇,是天一觀的道長。 經(jīng)常有香客問我顺呕,道長枫攀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任株茶,我火速辦了婚禮来涨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忌卤。我一直安慰自己扫夜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布驰徊。 她就那樣靜靜地躺著笤闯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棍厂。 梳的紋絲不亂的頭發(fā)上颗味,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音牺弹,去河邊找鬼浦马。 笑死,一個(gè)胖子當(dāng)著我的面吹牛张漂,可吹牛的內(nèi)容都是我干的晶默。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼航攒,長吁一口氣:“原來是場噩夢啊……” “哼磺陡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤币他,失蹤者是張志新(化名)和其女友劉穎坞靶,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝴悉,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彰阴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拍冠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尿这。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倦微,靈堂內(nèi)的尸體忽然破棺而出妻味,到底是詐尸還是另有隱情,我是刑警寧澤欣福,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布责球,位于F島的核電站,受9級(jí)特大地震影響拓劝,放射性物質(zhì)發(fā)生泄漏雏逾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一郑临、第九天 我趴在偏房一處隱蔽的房頂上張望栖博。 院中可真熱鬧,春花似錦厢洞、人聲如沸仇让。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丧叽。三九已至,卻和暖如春公你,著一層夾襖步出監(jiān)牢的瞬間踊淳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國打工陕靠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留迂尝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓剪芥,卻偏偏與公主長得像垄开,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子税肪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

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