在写项目的时候,我们经常因为一堆乱糟糟的代码而烦心,所以很多时候我们需要把代码封装起来,这样看起来简单有条理,而且方便使用。下面是我对vue项目中,axios请求的封装以及路由拦截,希望能帮助到你。
1.Axios的封装
1.安装axios
npm install axios // 安装axios
2.引入
一般我会在src文件下建一个utils文件夹,里面建一个request.js文件,request.js用来封装我们的axios
注意错误返回的code或者其他错误编码,要根据自己具体后台返回的写,下面的编码只能作为参考
//request.js
import axios from 'axios'; // 引入axios
import qs from 'qs'; //引入qs模块,用来序列化post类型的数据,后面会提到
// 先导入vuex,因为我们要使用到里面的状态对象
// vuex的路径根据自己的路径去写
import store from '@/store/index';
// 路由文件,下面toLgin方法需要用到
import router from '@/router/index';
//导入封装cookie文件
import { removeCookies } from "../utils/auth";
// 环境的切换
// 项目环境可能有开发环境、测试环境和生产环境。我们通过node的环境变量来匹配我们的默认的接口url前缀。axios.defaults.baseURL可以设置axios的默认请求地址
// if (process.env.NODE_ENV == 'development') {
// axios.defaults.baseURL = 'https://www.baidu.com';}
// else if (process.env.NODE_ENV == 'debug') {
// axios.defaults.baseURL = 'https://www.ceshi.com';
// }
// else if (process.env.NODE_ENV == 'production') {
// axios.defaults.baseURL = 'https://www.production.com';
// }
// create an axios instance
const service = axios.create({
baseURL: BASE_URL,
timeout: 30000,// request timeout
// "Content-Type": "application/x-www-form-urlencoded"
})
// post请求的时候,我们需要加上一个请求头,所以可以在这里进行一个默认的设置,
// 即设置post的请求头为application/x-www-form-urlencoded;charset=UTF-8
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
/**
* 跳转登录页
* 携带当前页面路由,以期在登录页面完成登录后返回当前页面
*/
const toLogin = () => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
});
}
/**
* 请求失败后的错误统一处理
* @param {Number} status 请求失败的状态码
*/
const errorHandle = (status, other) => {
// 状态码判断
switch (status) {
// 401: 未登录状态,跳转登录页
case 401:
toLogin();
break;
// 403 token过期
// 清除token并跳转登录页
case 666:
alert('登录过期,请重新登录');
removeCookies('token');
removeCookies('user');
setTimeout(() => {
toLogin();
}, 1000);
break;
// 404请求不存在
case 404:
alert('请求的资源不存在');
break;
case status:
alert(other);
break;
default:
console.log(other);
}
}
// 添加请求拦截器
service.interceptors.request.use(config => {
console.log(config);
// 每次发送请求之前判断vuex中是否存在token
// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
const token = store.state.token;
token && (config.headers.Authorization = token);
if(config.method=='post'){
config.data = qs.stringify(config.data)
}
return config;
}, error => {
console.log(error);
Promise.error(error);
})
// 添加响应拦截器
service.interceptors.response.use(
response => {
console.log(response);
// 如果返回的状态码代表错误
if (response.data.errno != 0) {
// errorHandle(response.data.errno, response.data.errmsg);
return Promise.reject(response.data);
} else {
return Promise.resolve(response.data);
}
},
error => {
console.log('error');
if (error.response.status) {
if (error.response.status != 200) {
errorHandle(error.response.status, error.response.statusText);
return Promise.reject(response);
} else {
// 处理断网的情况
// eg:请求超时或断网时,更新state的network状态
// network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
// store.commit('changeNetwork', false);
}
return Promise.reject(error.response);
}
}
)
export default service;
3.配置文件
以上就是request.js的内容
上面我们写的api的base_url,需要在其他文件写一下,因为我现在写的需要进行跨域处理,所以我们先写一下跨域
// /config/index.js
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': { //代理地址
target: 'https://www.********.com', //需要代理的地址
changeOrigin: true, //是否跨域
secure: false,
pathRewrite: {
// '^/api': '' //本身的接口地址没有 '/api' 这种通用前缀,所以要rewrite,如果本身有则去掉
}
}
},
// /build/webpack.dev.conf.js
new webpack.DefinePlugin({
'process.env': require('../config/dev.env'),
'BASE_URL':'"/api"'
}),
4.封装接口
上面请求已经封装好了,下面我们开始封装接口。封装接口有利于我们管理请求接口。
我们在src下面创建一个api文件夹,文件夹里创建index.js文件,用来封装我们的请求接口。
/api/index.js
import request from '../utils/request'
export function getInfo(params) {
return request({
url: '请求接口',
method: 'get',
params: params,
loading: true // loading效果
})
}
export function login(params) {
return request({
url: '请求接口',
method: 'post',
data: params,
})
}
5.使用vuex状态管理
这一步根据需求决定要不要使用,不需要的话直接跳过。
1.安装vuex
npm install vuex
2.在src下面创建 store文件夹,接着创建index.js,引入并使用vuex
import Vue from 'vue'
import Vuex from 'vuex'
import {setCookies} from "../utils/auth";
Vue.use(Vuex)
const store = new Vuex.Store({
// 全局变量
state: {
user: null,
token: '' //初始化token
},
mutations: {
//存储token方法
//设置token等于外部传递进来的值
setToken(state, token) {
state.token = token
setCookies('token',token,1); //同步存储token
},
setUser(state, user) {
state.user = user
setCookies('user',user,1); //同步存储token
},
},
})
export default store
6.缓存 cookie
我们需要使用到缓存来存储一些信息,这里我用的是cookie
1.安装js-cookie
npm install js-cookie
2.引入并使用,在utils文件夹下创建auth.js文件
封装cookie
// auth.js
import Cookies from 'js-cookie'
//获取存取的cookie值
export function getCookies(name) {
return Cookies.get(name)
}
//获取存取的cookie值(获取的是对象,所以需要进行处理)
export function getJsonCookies(name) {
return Cookies.getJSON(name)
}
//存取cookie
export function setCookies(name,value,time,path) {
return Cookies.set(name, value,{ expires: time, path:path })
}
//清除cookie
export function removeCookies(name) {
return Cookies.remove(name)
}
7.页面调用接口
现在我们创建三个页面模拟一下登录的一些情况
1.index.vue 首页(不需要登录也可以进入)
2.login.vue 登录页面
3.user.vue 用户页面 (需要登录才可以进入否则会被拦截)
首页大概就这这样,有去登录和进入内部user页面两个链接
//index.vue
<!-- 组件的模板 -->
<template>
<div class="car">
<div v-if="isLogin">
<img :src="user.avatar" alt="">
<p>{{user.nickname}}</p>
<button @click="outLogin">退出登录</button>
</div>
<router-link :to="{path:'/login',query:{ redirect:decodeURIComponent('/') }}" tag="button" v-else>去登陆</router-link>
<router-link to="/user" >进入内部</router-link>
</div>
</template>
<!-- 组件的模型 -->
<script>
import { getInfo, login } from "../api/index";
import { getCookies,getJsonCookies,removeCookies } from "../utils/auth";
export default {
data() {
return {
isLogin:false,
user:{},
};
},
methods: {
// 获取列表
get() {
var p = {
source: "h5",
host: "1"
};
getInfo(p).then(res => {
console.log(res);
});
},
// 获取用户登录信息
getInfo(){
if(getCookies('token')&&getCookies('user')){
this.isLogin = true;
console.log(getJsonCookies('user'))
this.user = getJsonCookies('user');
}
},
// 退出登录
outLogin(){
removeCookies('user');
removeCookies('token');
window.location.reload();
},
},
mounted() {
this.getInfo();
}
};
</script>
<!-- 组件的样式 -->
<style scoped>
</style>
上面我们给一个条件,登录和未登录两种状态,显示的效果是不一样的,未登录显示去登录按钮,登录状态就显示用户信息。
点击去登录会跳到登录页面。
点击进入内部可以跳转到user页面,但是user页面需要登录才能进,所以我写了一个路有拦截,那些需要登录才能进入的页面,我都有进行处理,会在后面提到。点击进入内部跳转按钮,根据我后面写的路由拦截,如果是登录状态,就直接进入,如果未登录,就弹窗提示是否登录,确认进入登录页面,取消留在当前页面。
登录页面
//login.vue
<!-- 组件的模板 -->
<template>
<div class="car">
<button @click="onlogin">登录</button>
</div>
</template>
<!-- 组件的模型 -->
<script>
import { getInfo, login } from "../api/index";
import { getCookies, getJsonCookies, removeCookies } from "../utils/auth";
export default {
data() {
return {};
},
methods: {
onlogin() {
var user = {
phone: "**************",
password: "**********",
source: "pc",
login_platform: "1",
type: "3"
};
login(user).then(res => {
var token = res.data.token;
var userInfo = res.data.userInfo;
var that = this;
// 将token存入cookie和vuex
this.$store.commit("setToken", token);
this.$store.commit("setUser", userInfo);
if (that.$route.query.redirect == undefined) {
that.$router.push("/");
} else {
that.$router.push(that.$route.query.redirect);
}
});
}
},
mounted() {}
};
</script>
<!-- 组件的样式 -->
<style scoped>
</style>
登录成功直接返回到首页(从哪个页面进去登录页面,就返回到哪个页面)
登录成功后需要将token和用户信息存起来,以便后面继续使用。
8.路由拦截
对于有些未登录不能进入的页面,我们需要写个路由拦截。
在路由文件里进行处理
// /router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import { getCookies } from "@/utils/auth";
Vue.use(Router)
let router=new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'index',
component: () => import('@/pages/index'),
},
{
path:'/login',
name:'login',
component: () => import('@/pages/login'),
},
{
path:'/user',
name:'user',
component: () => import('@/pages/user'),
meta: { requireLogin:true}
}
]
})
//路由拦截
router.beforeEach((to, from, next) => {
let token = getCookies('token');
if(to.meta.requireLogin){
if(token){
next();
}else{
let ifLogin = confirm('是否需要登录?')
if(ifLogin){
next({
path:'/login',
query:{ redirect:decodeURIComponent(to.fullPath) }
})
}else{
next(false)
}
}
}else{
next();
}
})
export default router;
以上应该是比较完善的代码了,后续有补充的我会加上去,希望我的笔记能够帮到你们。