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、在生产环境时,可以让后台进行跨域允许即可
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、携带参数的请求
import qs from 'qs';
Vue.prototype.$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({
// 失败
})
}