vue-cli使用axios跨域及拦截器的使用

一、axios解决跨域问题

 1、在main.js中引入axios,并将其设置为vue原型链上的属性,这样在组件中就可以直接 this.$axios使用了

import axios from 'axios';
Vue.prototype.$axios=axios;

2、在config/index.js里面设置ProxyTable代理

dev: {
    // Paths 静态资源文件夹
    assetsSubDirectory: 'static',
    // 发布路径
    assetsPublicPath: '/',
    // 代理配置表,在这里可以配置特定的请求代理对应的API接口
    proxyTable: {
      '/api':{
        target:'https://api.apiopen.top/',  // 后台接口地址
        secure:false,   //如果是https接口,则需要配置此函数
        changeOrigin:true,  // 如果接口跨域,则需要配置此函数;值为true的话,请求的header将会设置为匹配目标服务器的规则(Access-Control-Allow-Origin)
        pathRewrite:{
          '^/api': ''  // 本身的接口地址没有 '/api' 这种通用前缀,所以要rewrite,如果本身有则去掉 
        }
      }
    },
}

3、调用接口

/**
 * https://api.apiopen.top/musicDetails?id=604392760
 * 音乐详情接口
 */
this.$axios.get('/api/musicDetails',{
  params:{
    id:604392760
  }
}).then(res => {
  console.log(res.data)
}).catch(err => {
  console.log(err)
})

4、原理讲解:

       因为我们给url加上了前缀/api,我们访问/musicDetails?id=604392760就当于访问了:localhost:8080/api/musicDetails?id=604392760(其中localhost:8080是默认的IP和端口)。

      在index.js中的proxyTable中拦截了/api,并把/api及其前面的所有替换成了target中的内容,因此实际访问Url是http://api.apiopen.top/musicDetails?id=604392760

注意:这只是开发环境(dev)中解决了跨域问题,生产环境中真正部署到服务器上如果是非同源还是存在跨域问题

5、解决开发环境(dev)和生产环境(pro)跨域问题

    1、在config/dev.env.js下进行配置

'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  API_HOST:'/api'    // 这里的 /api 其实指的是 config/index.js中proxy中的URL
})

     2、在config/prod.env.js下进行配置

'use strict'
module.exports = {
  NODE_ENV: '"production"',
  API_HOST:'https://api.apiopen.top'    // 生产环境后台地址
}

解析:当然不管是开发还是生产环境都可以直接请求https://api.apiopen.top。配置好之后测试时程序会自动判断当前是开发还是生产环境,最后自动匹配后台api地址

   3、一定要重新启动服务     (采坑之一)

    4、在生产环境时,可以让后台进行跨域允许即可

二、axios拦截器的使用

      1、创建文件 /request/http.js,在此js里面设置axios以及拦截设置

       

// 引入Axios
import axios from 'axios';

// 设置后台api地址,避免来回切换
if (process.env.NODE_ENV == 'development') {
  // 开发环境(测试环境)
  axios.defaults.baseURL = '';
} else if (process.env.NODE_ENV == 'production') {
  // 线上环境 (正式环境)
  axios.defaults.baseURL = '';
}

此地方注意:

         如果已在config/prod.env.js以及config/dev.env.js进行环境地址的配置,就不必再写一次。

      2、设置请求拦截器配置

// 设置请求超时时间
axios.defaults.timeout = 5000
// 设置post请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'

/**
 * 设置请求拦截器
 */
axios.interceptors.request.use(
  config => {
    // 每次发送请求之前判断vuex中是否存在token        
    // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
    // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
    if (getSession('token')) {
      config.headers.Authorization = token
    }else {
      // 重定向到登录页面
      router.push('/login')
    }
    return config;
  },
  error => {
    return Promise.error(error);
  }
)

      3、设置 响应拦截的配置

axios.interceptors.response.use(
  response => {
    // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据;否则的话抛出错误
    if (response.status === 200) {
      return Promise.resolve(response);
    } else {
      return Promise.reject(response);
    }
  },
  // 服务器状态码不是2开头的的情况
  // 这里可以跟你们的后台开发人员协商好统一的错误状态码    
  // 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
  // 下面列举几个常见的操作,其他需求可自行扩展
  err => {
    //http response 服务器响应拦截器,这里拦截401错误,并重新跳入登页重新获取token
    if (err && err.response) {
      switch (err.response.status) {
        case 400:
          err.message = '请求错误'
          break
        case 401:
          err.message = '未授权,请登录'
          // 这里写清除token的代码
          router.replace({
            path: '/login',
            query: {redirect: router.currentRoute.fullPath}   //登录成功后跳入浏览的当前页面
          })
          break
        case 403:
          err.message = '拒绝访问'
          break
        case 404:
          err.message = `请求地址出错`
          break
        case 408:
          err.message = '请求超时'
          break
        case 500:
          err.message = '服务器内部错误'
          break
        default:
      }
    }
    // 返回接口返回的错误信息
    return Promise.reject(err.response);
  }
)

    4、对axios请求的封装

/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export function get(url, params = {}) {
  return new Promise((resolve, reject) => {
    axios.get(url, {
      params: params
    })
      .then(response => {
        resolve(response.data);
      })
      .catch(err => {
        reject(err)
      })
  })
}


/** 
 * post方法,对应post请求 
 * @param {String} url [请求的url地址] 
 * @param {Object} params [请求时携带的参数] 
 */
export function post(url, data = {}) {
  return new Promise((resolve, reject) => {
    axios.post(url, data)
      .then(response => {
        resolve(response.data);
      }, err => {
        reject(err)
      })
  })
}

/**
 * put方法,对应put请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export function put(url, params) {
  return new Promise((resolve, reject) => {
    axios.put(url, params,)
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

/**
 * $delete,对应delete请求
 */
export function $delete(url, params){
  return new Promise((resolve, reject) =>{
    axios.delete(url, {
      data: params
    })
      .then(res => {
        resolve(res.data)
      })
      .catch(err => {
        reject(err.data)
      })
  });
}

     6、同时请求多个接口 等所有接口全部加载完成再处理

    import Axios from "axios";
    Axios.all([request1, request2, request3])
      .then(
        Axios.spread((area, acct, perms) => {
      console.log('全部加载完成')
 
        })
      )
      .catch(err => {
        console.log(err.response)
      });
 
说明:request1、request2、request3均代表请求路径

      7、axios的接口调用

          7.1、携带参数的请求

  •      首先在main.js中导入qs模块
import qs from 'qs';
Vue.prototype.$qs = qs;
  •   使用qs处理参数
var that = this
this.$axios.get('/api/musicDetails',this.$qs.stringfy({
    params:{
        id:604392760
    })
}).then(res => {
     console.log(res.data)
     that.newList = res.data 
}).catch(err => {
     console.log(err)
})

注意:在请求中如果要将值复制到data里面,先进行this指向转换;

三、如果项目中很多接口请求,那就统一在一个js文件里

      1、创建 api.js

/**   
 * api接口统一管理
 */
import { get, post } from './http.js'

// 登录
export const LoginIn = (params) =>{
    return post('/user/login',params)
}
// 退出登录
export const LoginOut = () => {
    return get('/user/logOut')
}

//音乐详情接口
export const Details = (params) =>{
    return get(`/musicDetails`,params)
}

      2、调用接口

import Api form './api.js'

created(){
    Api.Detail(params).then({
        // 成功
    }).cath({
        // 失败
    })
}

 

你可能感兴趣的:(Vue)