前言
在VUE項目中進行數據交互使用的比較多的就是axios,新手一般都是安裝完axios插件後在需要的地方直接使用axios.get()或axios.post(),我也不例外。在小項目中的確這種方式簡單快捷,但是當在大項目中還是這樣使用起來就顯得非常的繁瑣,自己也開始研究如何進行優化,把公共的部分提取出來,減少代碼的沉餘。但是始終還是覺得自己的想法不夠先進,後面在看一個VUE開源項目的時候發現它對axios進行封裝的很好,於是借鑑了一下。
目錄結構
在src目錄下新建文件夾api,api文件夾下新建apis文件夾(存放所有api接口)、urls文件夾(存放所有api接口的url)、axios文件(對axios進行配置)、index.js文件。
axios.js(配置【完整全部內容見最後】)
1.對請求頭部進行配置(基礎的url、請求超時、headers)
const tokenKey = 'JEECMS-Auth-Token'
const request = axios.create({
baseURL: process.env.VUE_APP_API_PREFIX,
timeout: 50000,
headers: {
'Content-Type': 'application/json',
'Redirect-Header': false
}
})
2.對請求參數進行配置
const baseHeader = () => { //動態獲取token和標誌性的ID
const token = window.localStorage.getItem(tokenKey)
const siteId = window.localStorage.getItem('siteId')
return { //返回新的內容
[tokenKey]: token,
siteId
}
}
request.interceptors.request.use(config => {
config.headers = Object.assign({}, baseHeader(), config.headers) //修改headers
if (!config.url) { //使用elementUI的消息框進行提示
Message.error({
showClose: true,
message: '接口地址錯誤',
type: 'error',
duration: 3 * 1000
})
} else if (config.url.endsWith('/admin/login')) { //特殊情況處理
config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
config.data = qs.stringify(config.data)
}
return config
}, error => { //對請求出錯後的處理
console.log(error)
return Promise.reject(error)
})
3.對返回參數進行配置
request.interceptors.response.use(response => {
if (response.data.token && response.data.token !== '') {
localStorage.setItem(tokenKey, response.data.token)
}
return response
}, error => {
// console.log(error)
let message = error.message
if (error.response.status === 404) {
message = '接口訪問失敗'
}
Message({
showClose: true,
message,
type: 'error',
duration: 3 * 1000
})
return Promise.reject(error)
})
4.對請求結果狀態處理
const checkStatus = response => {
if (response && response.status === 401) {
window.localStorage.setItem(tokenKey, '')
const url = window.location.hash.substr(1)
if (/^\/login/.test(url)) {
router.push(url)
} else {
router.push(`/login?redirect=${escape(url)}`)
}
return
}
if (response && (response.status === 200 || response.status === 304 || response.status === 400 || response.status === 404)) {
return response.data
}
return {
status: -404,
msg: '網絡異常'
}
}
function checkCode (res) {
if ([501, 502, 503, 506].includes(res.code)) {
window.localStorage.setItem(tokenKey, '')
const url = window.location.hash.substr(1)
if (/^\/login/.test(url)) {
router.push(url)
} else {
router.push(`/login?redirect=${escape(url)}`)
}
}
if (res.code !== 200) {
Message({
showClose: true,
message: res.message || '服務器端錯誤',
type: 'error',
duration: 3 * 1000
})
}
return res
}
5.導出各種請求方式
export default {
request (config) {
return axios.request(config).then(checkStatus).then(checkCode)
},
login (url, data) {
return requestLogin({
method: 'post',
url,
data
}).then(checkStatus).then(checkCode)
},
upload (url, data, onUploadProgress = () => {}) {
return request({
method: 'post',
url,
headers: { 'Content-Type': 'multipart/form-data' },
data,
onUploadProgress
}).then(checkStatus).then(checkCode)
},
download (url, data, onDownloadProgress = () => {}) {
return request({
method: 'post',
url,
data,
responseType: 'blob',
onDownloadProgress
}).then(checkStatus)
},
post (url, data, onUploadProgress = () => {}) {
return request({
method: 'post',
url,
data,
onUploadProgress
}).then(checkStatus).then(checkCode)
},
get (url, params, headers = {}) {
return request({
method: 'get',
url,
params,
headers
}).then(checkStatus).then(checkCode)
},
put (url, data) {
return request({
method: 'put',
url,
data
}).then(checkStatus).then(checkCode)
},
patch (url, data) {
return request({
method: 'patch',
url,
data
}).then(checkStatus).then(checkCode)
},
delete (url, data) {
return request({
method: 'delete',
url,
data
}).then(checkStatus).then(checkCode)
}
}
URL封裝(以登陸模塊爲例)
const prefix = '/admin'
export default {
// 驗證碼
code: '/common/kaptcha',
// 登陸
login: `${prefix}/login`,
// 上傳
upload: `${prefix}/upload/o_upload`,
// 返回中文首字母
pinyin: '/language/pinyin',
// 自動摘要
summary: '/language/summary',
// 修改密碼
adminpsw: `${prefix}/users/adminpsw`,
// 導入word
docImport: `${prefix}/contentext/docImport`
}
接口封裝(以登陸模塊爲例)
import axios from '../axios'
import loginUrls from '../urls/login'
export default {
fetchCode () {
return axios.get(loginUrls.code)
},
fetchLogin (data) {
return axios.login(loginUrls.login, data)
},
fetchUpload (data, onUploadProgress) {
return axios.upload(loginUrls.upload, data, onUploadProgress)
},
fetchPinyin (data) {
return axios.get(loginUrls.pinyin, data)
},
fetchSummary (data) {
return axios.post(loginUrls.summary, data)
},
fetchAdminPsw (data) {
return axios.post(loginUrls.adminpsw, data)
},
fetchDocImport (data) {
return axios.upload(loginUrls.docImport, data)
}
}
index.js
const modulesFiles = require.context('./apis', true, /\.js$/)
// 這裏是webpack的方法,參數說明:要搜索的文件夾目錄、是否還應該搜索它的子目錄、以及一個匹配文件的正則表達式
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
const value = modulesFiles(modulePath)
modules = Object.assign(modules, value.default)
return modules
}, {})
export default modules
如何使用
在需要的地方使用如下方法調用接口
this.fetchLogin(data).then(res => {.....})
給自己做個宣傳
本人個人博客:www.dzyong.com
附錄:axios.js全部內容
import axios from 'axios'
import qs from 'qs'
import { Message } from 'element-ui'
import router from '@/routes'
const tokenKey = 'JEECMS-Auth-Token'
const request = axios.create({
baseURL: process.env.VUE_APP_API_PREFIX,
timeout: 50000,
headers: {
'Content-Type': 'application/json',
'Redirect-Header': false
}
})
const baseHeader = () => {
const token = window.localStorage.getItem(tokenKey)
const siteId = window.localStorage.getItem('siteId')
return {
[tokenKey]: token,
siteId
}
}
request.interceptors.request.use(config => {
config.headers = Object.assign({}, baseHeader(), config.headers)
if (!config.url) {
Message.error({
showClose: true,
message: '接口地址錯誤',
type: 'error',
duration: 3 * 1000
})
} else if (config.url.endsWith('/admin/login')) {
config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
config.data = qs.stringify(config.data)
}
return config
}, error => {
console.log(error)
return Promise.reject(error)
})
request.interceptors.response.use(response => {
if (response.data.token && response.data.token !== '') {
localStorage.setItem(tokenKey, response.data.token)
}
return response
}, error => {
// console.log(error)
let message = error.message
if (error.response.status === 404) {
message = '接口訪問失敗'
}
Message({
showClose: true,
message,
type: 'error',
duration: 3 * 1000
})
return Promise.reject(error)
})
const checkStatus = response => {
if (response && response.status === 401) {
window.localStorage.setItem(tokenKey, '')
const url = window.location.hash.substr(1)
if (/^\/login/.test(url)) {
router.push(url)
} else {
router.push(`/login?redirect=${escape(url)}`)
}
return
}
if (response && (response.status === 200 || response.status === 304 || response.status === 400 || response.status === 404)) {
return response.data
}
return {
status: -404,
msg: '網絡異常'
}
}
function checkCode (res) {
if ([501, 502, 503, 506].includes(res.code)) {
window.localStorage.setItem(tokenKey, '')
const url = window.location.hash.substr(1)
if (/^\/login/.test(url)) {
router.push(url)
} else {
router.push(`/login?redirect=${escape(url)}`)
}
}
if (res.code !== 200) {
Message({
showClose: true,
message: res.message || '服務器端錯誤',
type: 'error',
duration: 3 * 1000
})
}
return res
}
// 登錄用的請求實例
const requestLogin = axios.create({
baseURL: process.env.VUE_APP_API_PREFIX,
timeout: 50000,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
requestLogin.interceptors.request.use(config => {
config.data = qs.stringify(config.data)
return config
}, error => {
return Promise.reject(error)
})
requestLogin.interceptors.response.use(response => {
return response
}, error => {
let message = error.message
if (error.response.status === 404) {
message = '接口訪問失敗'
}
Message({
showClose: true,
message,
type: 'error',
duration: 3 * 1000
})
return Promise.reject(error)
})
export default {
request (config) {
return axios.request(config).then(checkStatus).then(checkCode)
},
login (url, data) {
return requestLogin({
method: 'post',
url,
data
}).then(checkStatus).then(checkCode)
},
upload (url, data, onUploadProgress = () => {}) {
return request({
method: 'post',
url,
headers: { 'Content-Type': 'multipart/form-data' },
data,
onUploadProgress
}).then(checkStatus).then(checkCode)
},
download (url, data, onDownloadProgress = () => {}) {
return request({
method: 'post',
url,
data,
responseType: 'blob',
onDownloadProgress
}).then(checkStatus)
},
post (url, data, onUploadProgress = () => {}) {
return request({
method: 'post',
url,
data,
onUploadProgress
}).then(checkStatus).then(checkCode)
},
get (url, params, headers = {}) {
return request({
method: 'get',
url,
params,
headers
}).then(checkStatus).then(checkCode)
},
put (url, data) {
return request({
method: 'put',
url,
data
}).then(checkStatus).then(checkCode)
},
patch (url, data) {
return request({
method: 'patch',
url,
data
}).then(checkStatus).then(checkCode)
},
delete (url, data) {
return request({
method: 'delete',
url,
data
}).then(checkStatus).then(checkCode)
}
}