vue接口封裝


安裝

cnpm install axios --save-dev; // 安裝axios
yarn add axios
cnpm install qs --save-dev; // 安裝qs模塊,用來序列化post類型的數據,否則后端無法接收到數據

引入模塊

在src目錄下創建一個service目錄,用於存放接口封裝的相關文件。然后在service目錄中創建service.js,用於axios、qs模塊的引入,並在此文件中對axios進行封裝。代碼如下(接口域名只有一個的情況):

// 導入  axios
import axios from 'axios'
import { Loading, Message } from 'element-ui'
// import router from '../router/index'
// 導入qs 對post請求進行序列化,如果不需要序列化,可以不用導入
// import qs from 'qs'

// axios.defaults.baseURL = 'http://127.0.0.1/api/'
axios.defaults.timeout = 10000;

// post請求頭
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

// 請求攔截器
axios.interceptors.request.use(
  config => {
    // 攜帶上token
    // const token = localStorage.getItem('token')
    // 在每次發起請求在請求頭上加上token值
    // token && (config.headers.Authorization = token)
    // 在每次請求獲取數據之前都開啟loading彈窗
    const option = {
      lock: true,
      spinner: 'el-icon-loading',
      background: 'rgba(0, 0, 0, 0.5)'
    }
    loadings = Loading.service(option)
    return config
      // 每次發送請求之前判斷是否存在token,如果存在,則統一在http請求的header都加上token,不用每次請求都手動添加了
      // 即使本地存在token,也有可能token是過期的,所以在響應攔截器中要對返回狀態進行判斷
      // const token = store.state.token;
      // token && (config.headers.Authorization = token);

  },
  error => {
      return Promise.error(error);
  })

  // instance.interceptors.response.use(
  //     // 請求成功
  //     res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),
  //     // 請求失敗
  //     error => {
  //         const { response } = error;
  //         if (response) {
  //             // 請求已發出,但是不在2xx的范圍
  //             errorHandle(response.status, response.data.message);
  //             return Promise.reject(response);
  //         } else {
  //             // 處理斷網的情況
  //             // eg:請求超時或斷網時,更新state的network狀態
  //             // network狀態在app.vue中控制着一個全局的斷網提示組件的顯示隱藏
  //             // 關於斷網組件中的刷新重新獲取數據,會在斷網組件中說明
  //             if (!window.navigator.onLine) {
  //                store.commit('changeNetwork', false);
  //             } else {
  //                 return Promise.reject(error);
  //             }
  //         }
  //     });

/*
 * 設置超時時間和跨域,是否允許攜帶憑證
 */
axios.defaults.timeout = 5000
axios.defaults.withCredentials = true

/*
 * 設置請求傳遞數據的格式(具體要看服務器要求什么格式,一般情況不用)
 * 比如 x-www-form-urlencoded
 */

// axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'
// axios.defaults.transformRequest = data => qs.stringify(data)

// 定義一個變量,用來控制請求時加載提示樣式,前提是要全局安裝了element-ui
var loadings

/*
 * 設置請求攔截器 客戶端發送請求->[ 請求攔截器 ] -> 服務器
 * TOEKN 校驗(JWT), 接收服務器返回的token,存儲到vue/本地存儲
 */
// axios.interceptors.request.use(
//   config => {
//     // 攜帶上token
//     const token = localStorage.getItem('token')
//     // 在每次發起請求在請求頭上加上token值
//     token && (config.headers.Authorization = token)
//     // 在每次請求獲取數據之前都開啟loading彈窗
//     const option = {
//       lock: true,
//       spinner: 'el-icon-loading',
//       background: 'rgba(0, 0, 0, 0.5)'
//     }
//     loadings = Loading.service(option)
//     return config
//   },
//   error => {
//     return Promise.reject(error)
//   }
// )

/*
 * 響應攔截器
 * 服務器返回信息 -> [攔截器的統一處理] ->客戶端js獲取到信息
 */
// axios.interceptors.request.use(
//   config => {
//       // 每次發送請求之前判斷是否存在token,如果存在,則統一在http請求的header都加上token,不用每次請求都手動添加了
//       // 即使本地存在token,也有可能token是過期的,所以在響應攔截器中要對返回狀態進行判斷
//       // const token = store.state.token;
//       // token && (config.headers.Authorization = token);
//       return config;
//   },
//   error => {
//       return Promise.error(error);
//   })


axios.interceptors.response.use(
  response => {
    loadings.close()
    return response.data
  },
  error => {
    loadings.close()
    const { response } = error
    if (response) {
      // 服務器返回了,最起碼有結果
      switch (response.status) {
        case 401:
          // 當前請求需要用戶驗證(一般是未登錄)
          // 下次有時間查資料整理此處跳轉登錄頁面
          localStorage.clear()  //清除本地存儲
          break
        case 403:
          // 服務器已經理解請求,但是拒絕執行它(一般是token過期)
          // 有時間補充資料來跳轉登錄界面
          localStorage.removeItem('token')
          break
        case 404:
          // 請求失敗,請求所希望得到的資源未被在服務器上發現
          // 可強制跳轉到404頁面
          Message.error('請求資源不存在!')
          break
        case 500:
          // 服務器異常(一般是業務報的錯)
          break
      }
    } else {
      // 服務器連結果都沒有返回
      if (!window.navigator.onLine) {
        // 斷網處理:可以跳轉到斷網頁面
        return
      }
      return Promise.reject(error)
    }
  }
)
// 導出封裝的axios
export default axios

上述代碼是接口域名只有一個的情況(多數情況),當接口域名有多個的時候(少數情況),我們需要對之前的封裝進行改造,代碼如下:

import axios from 'axios'    //引入axios
import qs from 'qs'    //引入qs,用來序列化post類型的數據,否則后端無法接收到數據
// 設置post請求頭
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
axios.defaults.withCredentials = false;//在跨域請求時,不會攜帶用戶憑證;返回的 response 里也會忽略 cookie

//創建axios實例,請求超時時間為300秒,因為項目中有多個域名,所以對應的也要創建多個axios實例
const instanceA = axios.create({
  timeout: 300000,
});
const instanceB = axios.create({
  timeout: 300000,
});

//如果項目為單一域名,這里可以不用進行配置,當項目接口有多個域名時,要對axios實例基礎路徑進行配置,否則在項目生產環境中無法進行區別調用
if (process.env.NODE_ENV == 'production') {
    instanceA.defaults.baseURL = 'https://www.production_a.com';
    instanceB.defaults.baseURL = 'https://www.production_b.com';
}

//請求和響應攔截可以根據實際項目需求進行編寫
// 請求發起前攔截
instanceA.interceptors.request.use((config) => {
//這里可以對接口請求頭進行操作 如:config.headers['X-Token'] = token
  console.log("請求攔截",config);
  return config;
}, (error) => {
  // Do something with request error
  return Promise.reject(error)
})
instanceB.interceptors.request.use((config) => {
  console.log("請求攔截",config);
  return config;
}, (error) => {
  // Do something with request error
  return Promise.reject(error)
})

// 響應攔截(請求返回后攔截)
instanceA.interceptors.response.use(response => {
  console.log("響應攔截",response);
  return response;
}, error => {
  console.log('catch', error)
  return Promise.reject(error)
})
instanceB.interceptors.response.use(response => {
  console.log("響應攔截",response);
  return response;
}, error => {
  console.log('catch', error)
  return Promise.reject(error)
})

//按照請求類型對axios進行封裝
const api={
    get(url,data){
    return instanceA.get(url,{params:data})
    },
    post(url,data){
    return instanceA.post(url,qs.stringify(data))    
    },
    doGet(url,data){
    return instanceB.get(url,{params:data})
    },
    doPost(url,data){
    return instanceB.post(url,qs.stringify(data))    
    }    
}
export {api}

api接口統一管理

將api接口按照功能模塊進行拆分,把同一模塊下的接口寫在同一個文件中進行統一管理,這樣代碼會更容易維護。比如我們的項目中有新聞模塊,音樂模塊等。我們就在serviec目錄中創建news.jsmusic.js文件,用於管理各自模塊的所有api接口,這里我只拿news.js文件為例,代碼如下:

import axios from "./service.js";    
const news={
    getNewsList(){//獲取新聞列表
        return axios.get("api/news/getNewsList")
    },
    editNewsDetail(data){//修改新聞詳情
        return axios.post("api/news/editNewsDetail",data);
    }
}
export default news;

為了更方便在項目中調用這些封裝好的接口,我們需要將這些接口掛載到vue的原型上,首先我們要在service目錄中創建api.js文件,將所有模塊的api管理文件引入進來,然后進行統一導出,代碼如下:

//引入相關api管理模塊
import news from "./news.js";
//進行統一導出
export default {
    news
}

找到項目中的main.js文件,將接口掛載到vue的原型上,代碼如下:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
Vue.prototype.axios=axios
Vue.config.productionTip = false
import api from "./service/api.js";
//將封裝的接口掛載到vue原型上
Vue.prototype.$api = api;
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

然后我們在項目創建完成時自動生成的模板文件App.vue調用封裝好的接口,代碼如下

<template>
  <div id="app">
    <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
    <button @click="getN">接口封裝getN</button>
    <button @click="postN">接口封裝postN</button>
    </div>
    <router-view/>
  </div>
</template>
<script>

export default {
    methods:{
        getN(){
            this.$api.news.getNewsList().then((res)=>{
                console.log(res);
            })
        },
        postN(){
            let openid="oO5tQ5VMPpuzLqwfXhpmwjqwSANM";
            let productCodes="pro-1337270496655446016";            
            this.$api.news.editNewsDetail({openid,productCodes}).then((res)=>{
                alert(res.data.msg);
            })
        }
    }    
}
</script>
<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;

  a {
    font-weight: bold;
    color: #2c3e50;

    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

配置代理

因為我們要在本地環境進行測試,這就涉及到了跨域問題,為了解決跨域問題,我們可以進行代理的配置,在項目根目錄中創建vue.config.js文件,然后可以對項目進行各種配置,代理的配置方法如下:

// vue.config.js
module.exports = {
  // 輸出文件目錄
  outputDir: "dist",
  // eslint-loader 是否在保存的時候檢查
  lintOnSave: false,
  // 基本路徑
  publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
  devServer: {
    host: "localhost",
    port: 8080,
    open: true,
    hotOnly: true, // 熱更新
    // 設置代理
    proxy: {
      "/api": {
        // 本地mock服務器
        target: "https://www.xxxx.com/xxx/",
        changeOrigin: true,
        ws: false,                
      },
      //如果項目中存在多個域名接口,可依次進行配置
    "/apib":{
        target: "https://www.xxxx.com/xxx/",
        changeOrigin: true,
        ws: false,
    },
    }, 
  },
};

代理配置好了之后,就可以運行項目了,命令行中輸入npm run serve,項目啟動好了之后,就可以進入頁面點擊按鈕,測試之前做的封裝是否好用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM