前言
在nuxt项目中,axios封装是个头疼的事情。因为很多Coder会用vue-cli那一套封装办法去封装:
import axios from 'axios'
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
axios.defaults.timeout = 50000
// 请求拦截
axios.interceptors.request.use(
(config) => {
config.url = 'your api' + config.url
return config
},
(error) => {
return Promise.reject(error)
}
)
// 响应拦截
axios.interceptors.response.use(
(response) => {
if (response.status !== 200) {
// code something
return
}
return response.data
},
(error) => {
return Promise.reject(error)
}
)
export default (url, data = null, method = 'POST', time = 50000) => {
let headers = {}
headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
}
axios.defaults.timeout = time
if (method !== 'GET') {
return axios.request({
url,
method,
data: data,
headers
})
} else {
return axios.get(url, {
params: data,
headers
})
}
}
然后再需要用到的页面调用或者再封装一个文件或者多个文件管理每个页面或者模块的调用方法。
其实Nuxt
本身自己也封装了axios请求方法可以直接在asyncData
调用$axios
。
也有的程序员会将其这样在进行封装:
export default function ({ store, app: { $axios } }) {
$axios.setBaseURL('your baseURL')
$axios.interceptors.request.use(
config => {
$axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
$axios.defaults.timeout = 50000
config.headers.Token = store.state.token || ''
config.headers.Appid = ''
return config
},
error => {
// do something with request error
return Promise.reject(error)
}
)
}
然后引用此文件再对Get
、Post
进行再封装…
在asyncData
使用:
import { myAxiosGet } from '@/utils/request'
asyncData() {
myAxiosGet({ url, params }).then(res => { console.log(res) })
}
以上我感觉调用太麻烦,且不说还有其他的methods
方法的时候又要再封装其他个方法的麻烦,如果有多请求域名那时候就原地爆炸了。
于是我在想为什么我们不能把自己的封装直接注入进nuxt
,并且能实现多个请求域名的时候照样临危不惧呢?比如:
asyncData({ $myApi }) {
$myApi.get('xxxx', {params}).then(res => { console.log( res ) })
}
// OR
asyncData({ $myApi }) {
$myApi.getData({params}).then(res => { console.log( res ) })
}
正文
废话不多说,直接上代码:
- 先在根目录创建
api
文件夹,再新建一个index.js文件
用于存储问要调用的api
API管理文件(可按需分多个文件)
export default ($axios) => {
return {
getData: () => $axios.get('/api/get_index_data'),
// 有参数的情况
postData: data => $axios.post('/api/get_index_data', data),
getData: params => $axios.get('/api/get_index_data', {params})
// ...your other api function
}
}
- 然后在
plugins
创建request.js
文件
封装api请求方法 并注入 nuxt
// 引入我们刚刚创建的index.js api文件
import indexApi from '@/api/index.js'
export default function({ $axios, store }, inject) {
function axiosConfig($axios) {
let requestConfig = {}
// 设置API的域名
$axios.setBaseURL('https://api.baidu.com')
// 设置请求拦截
$axios.onRequest((config) => {
// 用于调试
if (process.env.DEBUG) {
console.log('$axios.onRequest', config)
}
requestConfig = {
baseURL: config.baseURL,
url: config.url,
method: config.method,
data: config.data,
headers: config.headers,
params: config.params,
}
config.startTime = new Date().getTime()
config.headers['Content-Type'] = 'application/json'
/* 如果你需要token */
// const token = store.state.token || ''
// if (token) {
// config.headers.Authorization = `Bearer ${token}`
// }
return config
})
// 设置响应拦截
$axios.onResponse((response) => {
response.config.endTime = new Date().getTime()
const status = response.status
if (+status === 200) {
// 打印出每个接口的响应时间,如果慢了就捶后端,让他优化!!!
console.info(response.config.url,'请求时间',response.config.endTime - response.config.startTime + 'ms'
)
// 用于调试
if (process.env.DEBUG) {
console.info('$axios.onResponse', response.data)
}
// 返回接口数据
return response.data
} else {
// 如果请求失败的,打印出相应的错误信息,更好的修改。
const responseConfig = response ? response.config : {}
console.error('响应拦截报错提示: ', {
url: responseConfig.baseURL + responseConfig.url,
status: response.status,
statusText: response.statusText,
method: responseConfig.method,
headers: responseConfig.headers,
data: responseConfig.data,
params: responseConfig.params,
responseData: response.data,
})
}
})
// axios错误处理
$axios.onError((error) => {
const response = error.response || {}
const responseConfig = response.config || {}
console.error('$axios.onError: ', error)
console.error('错误处理提示 ', {
url: responseConfig.baseURL + responseConfig.url,
status: response.status,
statusText: response.statusText,
method: responseConfig.method,
headers: responseConfig.headers,
data: responseConfig.data,
params: responseConfig.params,
responseData: response.data,
...requestConfig,
})
})
// 最后返回$axios对象
return $axios
}
inject('indexApi', indexApi(axiosConfig($axios.create())))
}
至此,我们就能愉快的调用$indexApi
了
在asyncData
中使用:
async asyncData({ $indexApi }) {
const res = await $indexApi.getData()
let data = []
if(res.status) {
data = res.data
}
return {
data
}
},
在methods
中使用:
export default {
methods: {
async getData() {
await this.$indexApi.getData()
// code something
}
}
}
在store
中使用:
export const actions = {
async getData({ commit }) {
const res = await this.$indexApi.getData()
if (res.state) {
commit('SET_INDEX_DATA', res.data)
} else {
throw new Error(res)
}
}
}
支持多个接口域名
-
如果在项目中需要请求其他域名的接口,我们只需要在
api/index.js
文件中配置即可,如下:export default ($axios) => { $axios.setBaseURL('https://api.other.com') return { getData: () => $axios.get('/api/get_index_data'), // 有参数的情况 postData: data => $axios.post('/api/get_index_data', data), getData: params => $axios.get('/api/get_index_data', {params}) // ...your other api function } }
-
最后别忘了在
nuxt.config.js
引入我们的request.js
文件export default { ... // other code plugins: [ '~/plugins/request', ], ... // other code }
优点
先来说说这样做有什么好处吧。
首先,我也是从去年 才开始接触Nuxt
项目,每个项目都需要调几个域名的接口,在request.js
文件写if
、else
判断域名也可以,但是又要去判断header
,cookie
…之类的请求头就麻烦了,文件也会越来越大,而且写那么多if
、else
也影响程序性能。
-
如果多个域名,我们可以直接在api文件夹中根据域名新建多个js文件,在每个文件里去
setBaseURL
,还可以去修改指定的header
、Token
… -
使用
inject
注入,对SSR
服务端渲染更友好,毕竟Nuxt
的初衷就是为了服务端渲染,让页面更快。Sometimes you want to make functions or values available across your app. You can inject those variables into Vue instances (client side), the context (server side) and even in the Vuex store. It is a convention to prefix those functions with a .
$
Nuxt provides you with an method to do this easily. Inject is given as the second parameter when exporting a function. The will be prepended automatically to the key.
inject(key, value)
$
以上是官方文档的说明。
-
调用方便:直接使用
$xxxApi.XXX()
-
扩展性高:再多的域名,只需要在api文件夹新建对应的
js
文件,且可以针对每一个域名的请求方式去定制化。 -
管理方便:哪个
api
接口需要更换或者需要更改,找到对应的文件直接修改。 -
配合
store
来用更容易实现模块化管理(如果多域名的情况下,我一般是在api
文件夹用域名去区分,在store
根据功能去区分)
至此,一套在Nuxt
中的Axios
请求方案就这样完成了。有没有感觉这样调用起来方便且管理起来也容易呢?
参考链接:
[nuxtjs-axios|axios中文网 | axios (axios-js.com)]
Setup - Axios Module (nuxtjs.org)]
模板来啦!!!
仓库地址: Nuxt中axios的封装模板—Gitee
预览地址