Vue - axios

参考文档:axios

参考博客:《vue中Axios的封装和API接口的管理》《Axios源码深度剖析》

axios的封装和api接口的统一管理,其实主要目的就是在帮助我们简化代码和利于后期的更新维护

配置axios

// 设置请求跟路径
axios.defaults.baseURL = 'https://www.abc.com/project/api/'
// 设置请求超时时间,如果超过时间在响应拦截阶段提示用户
axios.defaults.timeout = 10000
// post请求headers中设置Content-Type,如果后端设置的接收类型是 application/x-www-form-urlencoded,则前端发送时需保持一致
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'

请求拦截

我们在发送请求前可以进行一个请求的拦截。比如,有些请求是需要用户登录之后才能访问的。

token使用流程

在登录完成之后,将用户的token通过localStorage或者cookie存在本地,之后用户每次在进入页面的时候,会首先从本地存储中读取token,如果token存在说明用户已经登录过,则更新vuex中的token状态,在每次请求接口的时候,都会在请求的header中携带token,后台人员就可以根据你携带的token来判断你的登录是否过期。如果没有携带,则说明没有登录过。

这时候或许有些小伙伴会有疑问了,就是每个请求都携带token,那么要是一个页面不需要用户登录就可以访问的怎么办呢?

其实,你前端的请求可以携带token,但是后台可以选择不接收啊!

App.vue

import store from '@/store'

export default {
  name: "App",
  created() {
    // 获取本地存储的token
    const token = localStorage.getItem('token')
    token && store.commit('setToken', { token })
  }
}

请求拦截

import store from '@/store'

axios.interceptors.request.use(    
  config => {        
    // 每次发送请求之前判断vuex中是否存在token        
    // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
    // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断 
    const token = store.state.token
    token && (config.headers.Authorization = token)
    return config
  },    
  error => {        
    return Promise.error(error)
  }
)

响应拦截

响应拦截主要处理响应失败的情况(响应成功直接返回),例如token过期,没有权限等,可以先与后端人员协商好错误码,然后在拦截过程中根据错误码引导用户不同的操作,如重新登录

import router from '@/router'
import store from '@/store'

axios.interceptors.response.use(    
  response => {   
    // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据。否则的话抛出错误
    if (response.status === 200) {            
      return Promise.resolve(response)
    } else {            
      return Promise.reject(response)
    }    
  },
  // 服务器状态码不是2开头的的情况
  // 下面列举几个常见的操作,其他需求可自行扩展
  error => {            
    if (error.response.status) {            
      switch (error.response.status) {                
        // 401: 未登录
        // 未登录则跳转登录页面,并携带当前页面的路径
        // 在登录成功后返回当前页面,这一步需要在登录页操作。                
        case 401:
          router.replace({                        
            path: '/login',
            query: { 
              redirect: router.currentRoute.fullPath
            }
          })
          break
        // 403 token过期
        // 登录过期对用户进行提示
        // 清除本地token和清空vuex中token对象
        // 跳转登录页面                
        case 403:
          Toast('登录过期,请重新登录')
          localStorage.removeItem('token')
          store.commit('clearToken')
          // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 
          setTimeout(() => {                        
            router.replace({                            
              path: '/login',
              query: {
                redirect: router.currentRoute.fullPath 
              }                        
            })                  
          }, 1000)
          break
      }
      return Promise.reject(error.response)
    }
  }    
})

GET请求封装

export function get(url, params) {
  return new Promise((resolve, reject) => {
    axios.get(url, { params: params })
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}

POST请求封装

axios.get()方法和axios.post()在提交数据时参数的书写方式还是有区别的。get的第二个参数是一个{},然后这个对象的params属性值是需要传递的参数对象;post的第二个参数就是需要传递的参数对象

如果后端设定的Centent-Type为application/x-www-form-urlencoded,则post请求前需要对参数对象(通常是json形式)进行序列化。如 { a:1, b: 2 },序列化后为 a=1&b=2

import qs from 'qs'

export function post(url, params) {
  return new Promise((resolve, reject) => {
    axios.post(url, qs.stringify(params)) // 参数序列化
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}

在项目中建立request文件夹,并建立http.js与api.js

http.js

import axios from 'axios'
import qs from 'qs'
import store from '@/store'
import router from '@/router'
import { Toast, MessageBox } from 'mint-ui'

// api根路径
axios.defaults.baseURL = 'https://www.abc.com/api/' 
// 请求超时时间,超时可在响应拦截中处理
axios.defaults.timeout = 10000
// 后端设置参数接收类型为application/x-www-form-urlencoded,这里也需要设置post请求Content-Type类型
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'

axios.interceptors.request.use(
  config => {
    // Authorization为后端规定请求头部携带验证身份的属性名(通常为token)
    const token = store.state.token
    token && (config.headers.Authorization = token)
    return config
  },
  error => {
    return Promise.error(error)
  }
)

axios.interceptors.response.use(
  response => {
    if (response.status === 200) {
      return Promise.resolve(response)
    } else {
      return Promise.reject(response)
    }
  },
  error => {
    // 请求超时的错误信息
    if (error.message.includes('timeout')) {
      MessageBox('提示', '请求超时,请检查网络')
    }
    // 根据错误码进行相应提示、操作、路由跳转
    if (error.response.status) {
      switch (error.response.status) {
        case 401:
          console.log('401')
          break
      }
      return Promise.reject(error.response)
    }
  }    
)

export function get(url, params) {
  return new Promise((resolve, reject) => {
    axios.get(url, { params: params })
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}

export function post(url, params) {
  return new Promise((resolve, reject) => {
    axios.post(url, qs.stringify(params))
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  })
}

api,js

import { get, post } from './http'

// 店铺列表
const barberList = p => post('v2.Store/StoreList', p)

export {
  barberList
}

home.vue

import { barberList } from "@/request/api"
import { Toast } from 'mint-ui'

const ERR_OK = 1

export default {
  name: "home",
  data() {
    return {
      baberList: [], // 店铺列表
    }
  },
  created() {
    this.getBarberList()
  },
  methods: {
    getBarberList() {
      barberList().then(res => {
        if (res.code === ERR_OK) {
          this.baberList = res.data.data
        }
        else {
          Toast(res.msg)
        }
      })
    }
  }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值