首页 > 其他 > 详细

vue接口封装

时间:2021-03-30 13:03:25      阅读:18      评论:0      收藏:0      [点我收藏+]

安装

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,项目启动好了之后,就可以进入页面点击按钮,测试之前做的封装是否好用。

vue接口封装

原文:https://www.cnblogs.com/caicaiz/p/14198120.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!