Nuxt中Axios的封装及接口统一管理方案

·  阅读 528
Nuxt中Axios的封装及接口统一管理方案

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情


前言

在nuxt项目中,axios封装是个头疼的事情。因为很多Coder会用vue-cli那一套封装办法去封装:

vue-cli封装axios

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封装方法

其实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)
		}
	)
}

复制代码

然后引用此文件再对GetPost进行再封装...

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

    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
      }
    }
    
    复制代码

封装request.js文件

  • 然后在plugins创建request.js文件

    // 引入我们刚刚创建的index.js api文件
    import indexApi from '@/api/index.js'
    
    export default function({ $axios, store }, inject) {
    	function axiosConfig($axios) {
            // 设置API的域名
            $axios.setBaseURL('https://api.baidu.com')
            // 设置请求拦截
            $axios.onRequest((config) => {
              // 用于调试
              if (process.env.DEBUG) {
                console.log('$axios.onRequest', config)
              }
              config.startTime = new Date().getTime()
              config.headers['Content-Type'] = 'application/json'
              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
              })
            })
            // 最后返回$axios对象
            return $axios
          }
        }
    
    	//最后将我们的api文件进行注入
    	inject('indexApi', indexApi(axiosConfig($axios.created())))
    }
    复制代码

    至此,我们就能愉快的调用$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文件写ifelse判断域名也可以,但是又要去判断header,cookie...之类的请求头就麻烦了,文件也会越来越大,而且写那么多ifelse也影响程序性能。

  1. 如果多个域名,我们可以直接在api文件夹中根据域名新建多个js文件,在每个文件里去setBaseURL,还可以去修改指定的headerToken...

  2. 使用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) $

    以上是官方文档的说明。

  3. 调用方便:直接使用$xxxApi.XXX()

  4. 扩展性高:再多的域名,只需要在api文件夹新建对应的js文件,且可以针对每一个域名的请求方式去定制化。

  5. 管理方便:哪个api接口需要更换或者需要更改,找到对应的文件直接修改。

  6. 配合store来用更容易实现模块化管理(如果多域名的情况下,我一般是在api文件夹用域名去区分,在store根据功能去区分)


至此,一套在Nuxt中的Axios请求方案就这样完成了。有没有感觉这样调用起来方便且管理起来也容易呢?

参考链接:

[nuxtjs-axios|axios中文网 | axios (axios-js.com)]

Setup - Axios Module (nuxtjs.org)]

[Nuxt - 插件目录 (nuxtjs.org)]


天气热了,大家吃个西瓜再走。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改