前言
在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)
}
}