Vue專案中axios請求及API介面的封裝
阿新 • • 發佈:2020-10-12
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(res) })
這樣寫不是不可以,但是存在一些缺陷,介面請求的 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:以上這些檔名、資料夾名、方法名、路徑等都是我自己取得,你可以按照自己的程式碼風格習慣進行調整。
以上,是我在專案中一些寫法,有的地方可能不完善,如有問題歡迎大家指正,感謝 :)