关于vue.js:Vue项目中API接口及axios请求的封装

46次阅读

共计 5222 个字符,预计需要花费 14 分钟才能阅读完成。

在理论的我的项目中,和后盾的数据交互是少不了的,我通常应用的是 axios 库,所以以下示例也是以 axios 为根底来进行封装的。如果对 axios 不理解的,请看这里 axios 文档

1、装置

首先是 npm 装置 axios 很简略:npm install axios

2、没有封装存在的问题

如果在没有封装接口的我的项目中,在文件中随处能够看到如下的接口调用办法:

this.$axios.post("/user/add", {
    params: {
        name: this.name,
        age: this.age
    }
})
.then(res => {console.log(res)
})
.then(err => {console.log(err)
})

这样写也不是不能够,但存在一些缺点,接口申请的 url 分布在各个文件中,如果须要在接口调用胜利或失败时做一些解决,就须要更改每个文件。所以把这些接口申请对立集中起来,如果有调整,间接在集中文件中找到批改就好了,而不必再去查每个文件。

3、创立文件

首先在我的项目的 src 目录中,新建文件夹及文件目录构造如下:

├── src 源码目录
│ ├── apis 接口文件目录
│ │ ├── login.api.js 登录模块的接口 api
│ │ └── user.api.js 用户模块的接口 api
│ ├── services 申请相干文件目录
│ │ ├── address.js 申请地址配置文件
│ │ └── request.js axios 封装,申请拦挡、响应码解决等操作 

api 接口文件模块的划分,大能够依据本人的理论我的项目,按业务性能或业务逻辑或其余模式划分。

4、申请地址配置

个别咱们的我的项目环境都会有多个,少的也会有开发环境和生产环境。失常状况下,在开发环境下和生产模式下有着不同的 baseURL,所以,咱们须要依据不同的环境切换不同的 baseURL。

address.js 文件:

// 依据 process.env.NODE_ENV 切换不同的 baseURL
const isPro = process.env.NODE_ENV === 'production'

module.exports = {
    // 'apis':vue.config.js 中 proxy 设置的代理
    baseURL: isPro ? 'http://192.168.100.120/ceds' : '/apis' 
}

5、axios 配置 (设置申请头、响应码解决)

大体思路是通过封装一个 request 类,其中蕴含了 get、post 等申请办法,这些申请办法又都会去调用 request 办法,该办法通过传入的不同参数调用原始的 axios 申请,而后返回一个 Promise。

request.js 文件:

import axios from 'axios'
import Qs from 'qs'
import Vue from 'vue'
import {getToken} from '@Utils/session.utils' // 存储获取 token 文件
import address from './address' // 申请地址

class Request {constructor () {
        // 创立 axios 实例
        this._axios = axios.create({
            baseURL: address.baseURL,
            timeout: 1000 * 5, // 申请超时工夫
            headers: {}})
        // 申请拦挡
        this._axios.interceptors.request.use(
            config => {
                const requestHeader = {
                      'X-Requested-With': 'XMLHttpRequest',
                      'Content-Type': 'application/json; charset=UTF-8',
                      'Access-Control-Allow-Origin': '*',
                      token: getToken() // 申请头对立增加 token}
                config.headers = Object.assign(config.headers, requestHeader)
                return config
            },
            error => {Promise.reject(error)
            }
        )
    }
    
    // 依据申请形式,判断参数是放在 query 中还是 body 中。// 最直观的区别,比方 GET 申请把参数蕴含在 url 中,而 POST 则通过 request body 把参数搁置在 body 体中,所以在提交时的参数模式是有区别的
    // 以下列了四种我个别罕用申请形式的参数模式,大家能够自行调整
    /**
      * 发送 get 申请
      * @param {String} url 地址
      * @param {Object} query 查问参数
      * @return json 数据
      */
    get (url, query = {}) {return this._request('get')(url, {...query})
    }
    /**
      * 发送 post 申请
      * @param {String} url 地址
      * @param {Object} body 查问参数
      * @return json 数据
      */
    post(url, body = {}, headers) {
        let data
        if(this.isFormData(body)) {data = body} else if(Array.isArray(body)) {data = body} else {data = { ...body}
        }
        return this._request('post')(url, headers)(url, data)
    }
    put (url, body = {}) {return this._request('put')(url, {...body})
    }
    delete(url, body = {}) {return this._request('delete')(url, {...body})
    }

    isFormData = v => {return Object.prototype.toString.call(v) === '[object FormData]'
    }


    /**
      * 设置申请头
      * @param {Object} header 申请头
      */
    setHeaders (header) {Object.keys(header).forEach(key => {this._axios.defaults.headers[key] = header[key]
        })
    }

    // 解决申请头 headers
    handleHeaders () {const headers = {}
        headers['XMIME-TYPE'] = '3'
        Headers['Content-Type'] = 'application/json; charset=UTF-8'
        return headers
    }

    /**
      * 发送申请
      * @param {String} method 申请办法类型
      * @param headers
      * @returns {function(*=, *=):Promise<unknown>}
      * @private
      */
    _request (method, headers) {this.setHeaders(this.handleHeaders()) // 设置对立的申请头
        if (headers) {this.setHeaders(headers) // 自定义申请头
        }
        
        return (url, data, timeout) => {
            const config = {
                url,
                method,
                timeout: timeout || this._axios.defaults.timeout
            } // 结构申请 config

            // 判断申请类型 get post
            const paramType = ['get', 'delete'].indexOf(method) !== -1 ? 'params' : 'data'
            config[paramType] = data
            // 参数序列化
            config.paramsSerializer = params => {return Qs.stringify(params, { arrayFormat: 'repeat'})
            }
            
            return new Promise((resolve, reject) => {
                // 发送真正的申请,验证权限,查看 404 等 status
                this._axios
                    .request(config)
                    .then(response => {if (this.handleSuccessStatus(response.data.code, response.data)) {if (response.headers['content-type'] !== 'text/plain; charset=urf-8') {
                                resolve(
                                    // 对响应后果二次包装
                                    Object.assign(
                                        {success: Number(response.data.code) === 200,
                                            data: response.data.data,
                                            msg: response.data.msg
                                        },
                                        response.data
                                    )
                                ) // 解决返回后果
                            } else {resolve(response.data)
                            }
                        } 
                    }, response => {
                        // 解决错误码
                        if(response.response) {
                            const statusCode = response.response.status
                            this.handleErrorStatus(statusCode)
                        } else {Vue.prototype.$message.error(response.message)
                        }
                        reject(response)
                    })
                    .catch(err => {reject(err)
                    })
                })
            }
        }
    }

    // 申请胜利,返回错误码
    // 具体状态码跟后盾开发人员对立,而后依据状态码进行相应提醒
    // 上面是我在我的项目中的操作,大家可自行调整扩大
    handleSuccessStatus (code, data) {
        let result = ''
        let flag = false
        switch (code) {
            case '20007':
                result = '未查找到二次认证明码!'
                flag = true
                break
            case '20008':
                result = '您的二次认证明码还未修改,请先批改!'
                flag = true
                break
            case '20009':
                result = '您还未开启二次认证,请分割管理员!'
                flag = true
                break
            case '90001':
                result = '请输出二次认证明码!'
                flag = true
                break
            case '90002':
                result = '无操作权限!'
                flag = true
                break
            default:
                break
        }

        // 进行告诉
        // $message 办法是我按需引入的 element-ui 中的提醒组件,你能够替换成本人的提醒组件
        if (result) {Vue.prototype.$message.error(result)
        }
        return flag
    }
    // 依据错误码获取谬误提醒
    handleErrorStatus (statusCode) {
        let errorMsg = ''
        if (statusCode === 500) {errorMsg = '数据申请失败,请分割管理员!'} else if (statusCode === 404) {errorMsg = '申请地址谬误!'} else if (statusCode === 402) {errorMsg = '以后您没有权限操作该数据!'} else {errorMsg = '申请出错!'}
        // 进行告诉
        Vue.prototype.$message.error(errorMsg)
    }
}

export default new Request()

6、应用

咱们在接口管理文件中,通过调用下面封装的 request 类,传入对应的参数即可。

user.api.js 文件:

import http from '../services/request'
​
/**
 * @description 获取用户列表
 * @param {*} params 申请接口的参数
 */
// 此处定义的 reqUserList 办法会调用咱们封装的 request 中的 get 办法,get 办法的第一个参数是申请地址,第二参数是 query 参数
export const reqUserList = params => http.get('/user/list', params)

在调用的 .vue 文件中,引入该办法并传入参数即可

import {reqUserList} from '@Apis/user.api' // 导入 api

export default {
    name: 'UserList',
    ... ...
    created() {},
    methods: {async getUsers() {
            // 调用 api 接口,并传入参数
            const res = await reqUserList({
                page: 1,
                size: 10
            })
            console.log(res) // 获取的响应后果
        }
    }
}

如此,就实现了对接口的封装及根本应用。

PS:以上这些文件名、文件夹名、办法名、门路等都是我本人获得,你能够依照本人的代码格调习惯进行调整。

以上,是我在我的项目中的一些写法,有的中央可能不欠缺,如有问题欢送大家斧正,感激 :)

正文完
 0