vue 权限管理 请求模块封装(3)

1 篇文章 0 订阅
1 篇文章 0 订阅

1. 写一个统一的url 配置文件


import { baseUrl } from './global'

export default {
  method: 'get',
  // 基础url前缀
  baseUrl: baseUrl,
  // 请求头信息
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Access-Control-Allow-Origin':'*',
  },
  // 参数
  data: {},
  // 设置超时时间
  timeout: 10000,
  // 携带凭证
  withCredentials: false,
  // 返回数据类型
  responseType: 'json',
  //跨域
  changeOrigin:true
}

2. 在前后端分离的情况下,在项目测试部署的时经常会修改文件的后端的url路径,所以我们需要写个请求后端的url配置文件,每次修改的时候只需要修改这个配置文件就可以了

/**
 * 全局常量、方法封装模块
 * 通过原型挂载到Vue属性
 * 通过 this.Global 调用
 */

// 后台管理系统服务器地址
export const baseUrl = 'http://localhost:9001'
// 系统数据备份还原服务器地址
export const backupBaseUrl = 'http://localhost:9001'

export default {
    baseUrl,
    backupBaseUrl
}

3..封装axios模块 ,可以统一调用 ,利用Promise 先实例化,Promise其实是一个构造函数,它有resolve,reject,race等静态方法;它的原型(prototype)上有then,catch方法,因此只要作为Promise的实例,都可以共享并调用Promise.prototype上面的方法(then,catch),并将错误信息添加到reject 中,成功的添加到resolve

import axios from 'axios';
import config from './config';
import Cookies from "js-cookie";
import router from '@/router'

export default function $axios(options) {
  return new Promise((resolve, reject) => {
    const instance = axios.create({
      baseURL: config.baseUrl,
      headers: config.headers,
      timeout: config.timeout,
      changeOrigin: config.changeOrigin,
      withCredentials: config.withCredentials
    })

    // request 拦截器
    instance.interceptors.request.use(
      config => {
        let token = Cookies.get('token')
        // 1. 请求开始的时候可以结合 vuex 开启全屏 loading 动画
        // console.log(store.state.loading)
        // console.log('准备发送请求...')
        // 2. 带上token
        if (token) {
          config.headers.token = token
        } else {
          // 重定向到登录页面
          router.push('/login')
        }
        // 3. 根据请求方法,序列化传来的参数,根据后端需求是否序列化
        if (config.method === 'post') {
          // if (config.data.__proto__ === FormData.prototype
          //   || config.url.endsWith('path')
          //   || config.url.endsWith('mark')
          //   || config.url.endsWith('patchs')
          // ) {

          // } else {
            // config.data = qs.stringify(config.data)
          // }
        }

        return config
      },

      error => {
        // 请求错误时
        console.log('request:', error)
        // 1. 判断请求超时
        if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) {
          console.log('timeout请求超时')
          // return service.request(originalRequest);// 再重复请求一次
        }
        // 2. 需要重定向到错误页面
        const errorInfo = error.response
        console.log(errorInfo)
        if (errorInfo) {
          error = errorInfo.data  // 页面那边catch的时候就能拿到详细的错误信息,看最下边的Promise.reject
          const errorStatus = errorInfo.status; // 404 403 500 ...
          router.push({
            path: `/error`
          })
        }
        return Promise.reject(error) // 在调用的那边可以拿到(catch)你想返回的错误信息
      }
    )

    // response 拦截器
    instance.interceptors.response.use(
      response => {
        let data;
        // IE9时response.data是undefined,因此需要使用response.request.responseText(Stringify后的字符串)
        if (response.data == undefined) {
          data = JSON.parse(response.request.responseText)
        } else {
          data = response.data
        }

        // 根据返回的code值来做不同的处理
        switch (data.rc) {
          case 1:
            console.log(data.desc)
            break;
          case 0:
            store.commit('changeState')
            // console.log('登录成功')
          default:
        }
        // 若不是正确的返回code,且已经登录,就抛出错误
        // const err = new Error(data.desc)
        // err.data = data
        // err.response = response
        // throw err

        return data
      },
      err => {
        if (err && err.response) {
          switch (err.response.status) {
            case 400:
              err.message = '请求错误'
              break
            case 401:
              err.message = '未授权,请登录'
              break
            case 403:
              err.message = '拒绝访问'
              break
            case 404:
              err.message = `请求地址出错: ${err.response.config.url}`
              break
            case 408:
              err.message = '请求超时'
              break
            case 500:
              err.message = '服务器内部错误'
              break
            case 501:
              err.message = '服务未实现'
              break
            case 502:
              err.message = '网关错误'
              break
            case 503:
              err.message = '服务不可用'
              break
            case 504:
              err.message = '网关超时'
              break
            case 505:
              err.message = 'HTTP版本不受支持'
              break
            default:
          }
        }
        console.error(err)
        return Promise.reject(err) // 返回接口返回的错误信息
      }
    )

    // 请求处理
    instance(options).then(res => {
      resolve(res)
      return false
    }).catch(error => {
      reject(error)
    })
  })
}

4.封装完成以后 我们只需在每个接口的时候调用就可以了,以登录接口为例

import axios from "@/http/axios";
import qs from 'qs';
let login = {};
login.subInfo = function (parms) {
  return axios({
    url: '/login',
    method: 'post',
    data:qs.stringify(parms)
  })
}
login.validateCode = function () {
  return axios({
    url: '/kaptcha/render',
    method: "get",
  })

}
export default login;

5.并随着接口的增多,我们需要写一个文件统一调用接口

import login from '@/Api/rbac/login.js'
import user from '@/Api/rbac/user.js'
import role from '@/Api/rbac/role.js'
import menu from '@/Api/rbac/menu.js'
import dict from '@/Api/rbac/dict.js'
import dept from '@/Api/rbac/dept.js'
import log from '@/Api/rbac/log.js'

let api = {
  login,
  user,
  role,
  menu,
  dict,
  dept,
  log
}
export default api;

5.然后我们把所有结构挂载在 Vue 原型的 $api 对象

// 导入所有接口

import api from "../api/Api";
const install = Vue => {
    if (install.installed)
        return;

    install.installed = true;

    Object.defineProperties(Vue.prototype, {
        // 注意,此处挂载在 Vue 原型的 $api 对象上
        $api: {
            get() {
                return api
            }
        }
    })
}

export default install

6. 最后在main.js中添加,然后就可以全局引用了

import api from './http'
import global from '@/http/global'
Vue.use(api)
Vue.prototype.global = global

7.写一个登录页面,我的把js,scss,vue分开写了

<template>
  <div class="login-container">
    <el-form :model="loginInfo" :rules="myrule"
             status-icon
             ref="loginInfo"
             label-position="left"
             label-width="0px"
             class="demo-ruleForm login-page">
      <h3 class="title">面朝大海 春暖花开</h3>
      <el-form-item prop="username">
        <el-input prefix-icon="el-icon-user-solid" v-model="loginInfo.username"
                  auto-complete="off"/>
      </el-form-item>
      <el-form-item prop="password">
        <el-input prefix-icon="el-icon-lock" type="password" v-model="loginInfo.password"
                  auto-complete="off"/>
      </el-form-item>
      <el-form-item prop="code" class="code">
        <el-input prefix-icon="el-icon-lock" v-model="loginInfo.verifyCode" placeholder="验证码"></el-input>
        <img :src="loginInfo.src" @click="clickCapatch"/>
      </el-form-item>
      <el-form-item>
        <el-checkbox v-model="checked" class="rememberme" style="float:left;">记住密码</el-checkbox>
        <a class="login-form-forgot" @click="froget" style="float:right;" href="javascript:;">忘记密码 </a>
      </el-form-item>
      <el-form-item style="width:100%;">
        <el-button type="primary" style="width:100%;" @click="loginafter" :loading="loading">登录</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script src="@/views/login/login.js"></script>
<style scoped src="@/views/login/login.scss"></style>

 

import url from "@/http/global";
import Cookies from "js-cookie";
export default {
  name: 'login',
  data() {
    return {
      loading: false,
      loginInfo: {
        username: 'root',
        password: '123456',
        verifyCode: "",
        src: url.baseUrl + "/kaptcha/render"
      },
      myrule: {
        username: [{required: true, message: 'please enter your account', trigger: 'blur'}],
        password: [{required: true, message: 'enter your password', trigger: 'blur'}]
      },
      checked: false
    }
  },
  methods: {
    clickCapatch: function () {
      this.loginInfo.src = url.baseUrl + '/kaptcha/render?time='+new Date();
    },
    froget() {

    },
    loginafter() {
      let that = this
      let params = {
        username: that.loginInfo.username,
        password: that.loginInfo.password,
        validateCodeText: that.loginInfo.verifyCode,
        captcha: Cookies.get("captcha")
      }
      this.$api.login.subInfo(params).then(res => {
        try {
          var dateStatus = res.status
          if (203 == dateStatus) {
              Cookies.set('token', res.jwtToken)
            this.$router.push({path: '/home',});
          } else {
            this.$router.push({path: '/error',});
          }
        } catch (e) {
          this.$router.push({path: '/error',});
        }
      })
    }
  }
};

 

.login-container {
  width: 100%;
  height: 100%;
  background : #f0f2f5 url('../../assets/background.jpg') no-repeat;
}
.login-page {
  -webkit-border-radius: 5px;
  border-radius: 5px;
  margin: 180px auto;
  width: 350px;
  padding: 35px 35px 15px;
  background: #fff;
  border: 1px solid #eaeaea;
  box-shadow: 0 0 25px #cac6c6;
}

.rememberme .el-checkbox {
  margin: 0px 0px 15px;
  text-align: left;
}

.code {
  position: relative;
  margin-top: 20px;
  display: block;
  width: 60%;
}

img {
  position: absolute;
  height: 35px;
  margin-left: 16px;
}

最后将登录页面添加到路由中

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'login',
      component: () => import('@/views/login/login.vue'),
    },
    {
      path: '/home',
      name: 'home',
      component: () => import('@/views/home/home.vue'),
    },
    {
      path: '/error',
      name: 'error',
      component: () => import('@/views/error.vue'),
    }
  ]
})

启动 查看页面效果

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值