vue--axios 拦截器的简单介绍及使用场景
1.axios 拦截器简单介绍
// 添加一个请求拦截器 axios.interceptors.request.use(function (config) { // Do something before request is sent return config; }, function (error) { // Do something with request error return Promise.reject(error); }); // 添加一个响应拦截器 axios.interceptors.response.use(function (response) { // Do something with response data return response; }, function (error) { // Do something with response error return Promise.reject(error); });
如果之后想移除拦截器你可以这么做
var myInterceptor = axios.interceptors.request.use(function () {/*...*/}); axios.interceptors.request.eject(myInterceptor);
2.vue 添加 axios 拦截器
1. 安装 axios
npm install axios --save-dev
2. 新建文件 axios.js
import axios from 'axios' // 配置默认的 host, 假如你的 API host 是: http://api.htmlx.club axios.defaults.baseURL = 'http://api.htmlx.club' // 添加请求拦截器 axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么 return config }, function (error) { // 对请求错误做些什么 return Promise.reject(error) }); // 添加响应拦截器 axios.interceptors.response.use(function (response) { // 对响应数据做点什么 return response }, function (error) { // 对响应错误做点什么 return Promise.reject(error) });
3. 在 main.js 中进行引用, 并配置一个别名 ($ajax) 来进行调用:
import axios from 'axios' import '../axios.js' //axios.js 的路径 Vue.prototype.$ajax = axios
4. 应用, 一个登录的 post 如:
this.$ajax({ method: 'post', url: '/login', data: { 'userName': 'xxx', 'password': 'xxx' } }).then(res => { console.log(res) })
3. 使用场景
3.1 axios 拦截器对路由进行拦截
针对登录拦截逻辑来看一下
1. 路由拦截
首先在定义路由的时候就需要多添加一个自定义字段 requireAuth, 用于判断该路由的访问是否需要登录. 如果用户已经登录, 则顺利进入路由, 否则就进入登录页面.
const routes = [ { path: '/', name: '/', component: Index }, { path: '/repository', name: 'repository', meta: { requireAuth: true, // 添加该字段, 表示进入这个路由是需要登录的 }, component: Repository }, { path: '/login', name: 'login', component: Login } ];
定义完路由后, 我们主要是利用 vue-router 提供的钩子函数 beforeEach()对路由进行判断.
router.beforeEach((to, from, next) => { if (to.meta.requireAuth) { // 判断该路由是否需要登录权限 if (store.state.token) { // 通过 vuex state 获取当前的 token 是否存在 next(); } else { next({ path: '/login', query: {redirect: to.fullPath} // 将跳转的路由 path 作为参数, 登录成功后跳转到该路由 }) } } else { next(); } }
其中, to.meta 中是我们自定义的数据, 其中就包括我们刚刚定义的 requireAuth 字段. 通过这个字段来判断该路由是否需要登录权限. 需要的话, 同时当前应用不存在 token, 则跳转到登录页面, 进行登录. 登录成功后跳转到目标路由.
登录拦截到这里就结束了吗? 并没有. 这种方式只是简单的前端路由控制, 并不能真正阻止用户访问需要登录权限的路由. 还有一种情况便是: 当前 token 失效了, 但是 token 依然保存在本地. 这时候你去访问需要登录权限的路由时, 实际上应该让用户重新登录.
这时候就需要结合 http 拦截器 + 后端接口返回的 http 状态码来判断.
2. 拦截器
要想统一处理所有 http 请求和响应, 就得用上 axios 的拦截器. 通过配置 http response inteceptor, 当后端接口返回 401 Unauthorized(未授权), 让用户重新登录.
// http request 拦截器 axios.interceptors.request.use( config => { if (store.state.token) { // 判断是否存在 token, 如果存在的话, 则每个 http header 都加上 token config.headers.Authorization = `token ${store.state.token}`; } return config; }, err => { return Promise.reject(err); }); // http response 拦截器 axios.interceptors.response.use( response => { return response; }, error => { if (error.response) { switch (error.response.status) { case 401: // 返回 401 清除 token 信息并跳转到登录页面 store.commit(types.LOGOUT); router.replace({ path: 'login', query: {redirect: router.currentRoute.fullPath} }) } } return Promise.reject(error.response.data) // 返回接口返回的错误信息 });
3.2 axios 拦截器对 http 请求的响应状态统一进行处理
首先我们要明白设置拦截器的目的是什么, 当我们需要统一处理 http 请求和响应时我们通过设置拦截器处理方便很多.
这个项目我引入了 element ui 框架, 所以我是结合 element 中 loading 和 message 组件来处理的. 我们可以单独建立一个 http 的 js 文件处理 axios, 再到 main.js 中引入.
/** * http 配置 */ // 引入 axios 以及 element ui 中的 loading 和 message 组件 import axios from 'axios' import { Loading, Message } from 'element-ui' // 超时时间 axios.defaults.timeout = 5000 // http 请求拦截器 var loadinginstace axios.interceptors.request.use(config => { // element ui Loading 方法 loadinginstace = Loading.service({ fullscreen: true }) return config }, error => { loadinginstace.close() Message.error({ message: '加载超时' }) return Promise.reject(error) }) // http 响应拦截器 axios.interceptors.response.use(data => {// 响应成功关闭 loading loadinginstace.close() return data }, error => { loadinginstace.close() Message.error({ message: '加载失败' }) return Promise.reject(error) }) export default axios
3.3 axios 拦截器对重复请求的处理
axios 官方文档上给了两种取消请求的方式.
轻查看: vue axios 在切换路由时如何取消所有请求 --cancelToken
根据文档上的第二种方法, 我们可以在拦截器里统一处理取消重复请求
let pending = []; // 声明一个数组用于存储每个 ajax 请求的取消函数和 ajax 标识 let cancelToken = axios.CancelToken; let removePending = (config) => { for(let p in pending){ if(pending[p].u === config.url + '&' + config.method) { // 当当前请求在数组中存在时执行函数体 pending[p].f(); // 执行取消操作 pending.splice(p, 1); // 把这条记录从数组中移除 } } } // 添加请求拦截器 axios.interceptors.request.use(config=>{ removePending(config); // 在一个 ajax 发送前执行一下取消操作 config.cancelToken = new cancelToken((c)=>{ // 这里的 ajax 标识我是用请求地址 & 请求方式拼接的字符串, 当然你可以选择其他的一些方式 pending.push({ u: config.url + '&' + config.method, f: c }); }); return config; },error => { return Promise.reject(error); }); // 添加响应拦截器 axios.interceptors.response.use(response=>{ removePending(res.config); // 在一个 ajax 响应后再执行一下取消操作, 把已经完成的请求从 pending 中移除 return response; },error =>{
return { data: { } }; 返回一个空对象, 主要是防止控制台报错
});
同一个请求, 没有完成的请求将被取消
利用这个方法, 一方面可以防止重复点击不同页码导致的表格数据闪烁, 另外可以做实时搜索, 始终获取最新结果.
最后取消重复请求会有些问题. 第二次请求时后台已经接收到了请求. 还是会生成 2 次相同的数据. 下面是对应的处理:
let pending = [] let CancelToken = axios.CancelToken let removePending = (config, f) => { let flagUrl = config.url + '&' + config.method if (pending.indexOf(flagUrl) !== -1) { if (f) { f() // 执行取消操作 } else { pending.splice(pending.indexOf(flagUrl), 1)// 把这条记录从数组中移除 } } else { if (f) { pending.push(flagUrl) } } } // http request 拦截器 HTTP.interceptors.request.use( config => { if (config.method === 'post') { console.log('我是拦截') config.cancelToken = new CancelToken((c) => { removePending(config, c) }) } return config }, err => { return Promise.reject(err) }) // http response 拦截器 HTTP.interceptors.response.use( response => { if (response.config.method === 'post') { removePending(response.config) } return response }, error => { pending = [] return { data: {error: error} } // 返回接口返回的错误信息 })
第一种适合 tabs, 分页等快速来回点击的情况, 取消之前的请求, 保持最近的一次请求.
第二种适合相同的接口被请求了多次, 只留第一次, 其他的都取消请求.
https://www.h3399.cn/201805/582452.html
1.axios 拦截器简单介绍
- // 添加一个请求拦截器
- axios.interceptors.request.use(function(config){
- // Do something before request is sent
- return config;
- },function(error){
- // Do something with request error
- returnPromise.reject(error);
- });
- // 添加一个响应拦截器
- axios.interceptors.response.use(function(response){
- // Do something with response data
- return response;
- },function(error){
- // Do something with response error
- returnPromise.reject(error);
- });
如果之后想移除拦截器你可以这么做
- var myInterceptor = axios.interceptors.request.use(function(){/*...*/});
- axios.interceptors.request.eject(myInterceptor);
2.vue 添加 axios 拦截器
1. 安装 axios
npm install axios --save-dev
2. 新建文件 axios.js
- import axios from'axios'
- // 配置默认的 host, 假如你的 API host 是: http://api.htmlx.club
- axios.defaults.baseURL ='http://api.htmlx.club'
- // 添加请求拦截器
- axios.interceptors.request.use(function(config){
- // 在发送请求之前做些什么
- return config
- },function(error){
- // 对请求错误做些什么
- returnPromise.reject(error)
- });
- // 添加响应拦截器
- axios.interceptors.response.use(function(response){
- // 对响应数据做点什么
- return response
- },function(error){
- // 对响应错误做点什么
- returnPromise.reject(error)
- });
3. 在 main.js 中进行引用, 并配置一个别名 ($ajax) 来进行调用:
- import axios from'axios'
- import'../axios.js'//axios.js 的路径
- Vue.prototype.$ajax = axios
4. 应用, 一个登录的 post 如:
- this.$ajax({
- method:'post',
- url:'/login',
- data:{
- 'userName':'xxx',
- 'password':'xxx'
- }
- }).then(res =>{
- console.log(res)
- })
3. 使用场景
3.1 axios 拦截器对路由进行拦截
针对登录拦截逻辑来看一下
1. 路由拦截
首先在定义路由的时候就需要多添加一个自定义字段 requireAuth, 用于判断该路由的访问是否需要登录. 如果用户已经登录, 则顺利进入路由, 否则就进入登录页面.
- const routes =[
- {
- path:'/',
- name:'/',
- component:Index
- },
- {
- path:'/repository',
- name:'repository',
- meta:{
- requireAuth:true,// 添加该字段, 表示进入这个路由是需要登录的
- },
- component:Repository
- },
- {
- path:'/login',
- name:'login',
- component:Login
- }
- ];
定义完路由后, 我们主要是利用 vue-router 提供的钩子函数 beforeEach()对路由进行判断.
- router.beforeEach((to,from,next)=>{
- if(to.meta.requireAuth){// 判断该路由是否需要登录权限
- if(store.state.token){// 通过 vuex state 获取当前的 token 是否存在
- next();
- }
- else{
- next({
- path:'/login',
- query:{redirect: to.fullPath}// 将跳转的路由 path 作为参数, 登录成功后跳转到该路由
- })
- }
- }
- else{
- next();
- }
- })
其中, to.meta 中是我们自定义的数据, 其中就包括我们刚刚定义的 requireAuth 字段. 通过这个字段来判断该路由是否需要登录权限. 需要的话, 同时当前应用不存在 token, 则跳转到登录页面, 进行登录. 登录成功后跳转到目标路由.
登录拦截到这里就结束了吗? 并没有. 这种方式只是简单的前端路由控制, 并不能真正阻止用户访问需要登录权限的路由. 还有一种情况便是: 当前 token 失效了, 但是 token 依然保存在本地. 这时候你去访问需要登录权限的路由时, 实际上应该让用户重新登录.
这时候就需要结合 http 拦截器 + 后端接口返回的 http 状态码来判断.
2. 拦截器
要想统一处理所有 http 请求和响应, 就得用上 axios 的拦截器. 通过配置 http response inteceptor, 当后端接口返回 401 Unauthorized(未授权), 让用户重新登录.
- // http request 拦截器
- axios.interceptors.request.use(
- config =>{
- if(store.state.token){// 判断是否存在 token, 如果存在的话, 则每个 http header 都加上 token
- config.headers.Authorization=`token ${store.state.token}`;
- }
- return config;
- },
- err =>{
- returnPromise.reject(err);
- });
- // http response 拦截器
- axios.interceptors.response.use(
- response =>{
- return response;
- },
- error =>{
- if(error.response){
- switch(error.response.status){
- case401:
- // 返回 401 清除 token 信息并跳转到登录页面
- store.commit(types.LOGOUT);
- router.replace({
- path:'login',
- query:{redirect: router.currentRoute.fullPath}
- })
- }
- }
- returnPromise.reject(error.response.data)// 返回接口返回的错误信息
- });
3.2 axios 拦截器对 http 请求的响应状态统一进行处理
首先我们要明白设置拦截器的目的是什么, 当我们需要统一处理 http 请求和响应时我们通过设置拦截器处理方便很多.
这个项目我引入了 element ui 框架, 所以我是结合 element 中 loading 和 message 组件来处理的. 我们可以单独建立一个 http 的 js 文件处理 axios, 再到 main.js 中引入.
- /**
- * http 配置
- */
- // 引入 axios 以及 element ui 中的 loading 和 message 组件
- import axios from'axios'
- import{Loading,Message}from'element-ui'
- // 超时时间
- axios.defaults.timeout =5000
- // http 请求拦截器
- var loadinginstace
- axios.interceptors.request.use(config =>{
- // element ui Loading 方法
- loadinginstace =Loading.service({ fullscreen:true})
- return config
- }, error =>{
- loadinginstace.close()
- Message.error({
- message:'加载超时'
- })
- returnPromise.reject(error)
- })
- // http 响应拦截器
- axios.interceptors.response.use(data =>{// 响应成功关闭 loading
- loadinginstace.close()
- return data
- }, error =>{
- loadinginstace.close()
- Message.error({
- message:'加载失败'
- })
- returnPromise.reject(error)
- })
- exportdefault axios
3.3 axios 拦截器对重复请求的处理
axios 官方文档上给了两种取消请求的方式.
轻查看: vue axios 在切换路由时如何取消所有请求 --cancelToken
根据文档上的第二种方法, 我们可以在拦截器里统一处理取消重复请求
- let pending =[];// 声明一个数组用于存储每个 ajax 请求的取消函数和 ajax 标识
- let cancelToken = axios.CancelToken;
- let removePending =(config)=>{
- for(let p in pending){
- if(pending[p].u === config.url +'&'+ config.method){// 当当前请求在数组中存在时执行函数体
- pending[p].f();// 执行取消操作
- pending.splice(p,1);// 把这条记录从数组中移除
- }
- }
- }
- // 添加请求拦截器
- axios.interceptors.request.use(config=>{
- removePending(config);// 在一个 ajax 发送前执行一下取消操作
- config.cancelToken =new cancelToken((c)=>{
- // 这里的 ajax 标识我是用请求地址 & 请求方式拼接的字符串, 当然你可以选择其他的一些方式
- pending.push({ u: config.url +'&'+ config.method, f: c });
- });
- return config;
- },error =>{
- returnPromise.reject(error);
- });
- // 添加响应拦截器
- axios.interceptors.response.use(response=>{
- removePending(res.config);// 在一个 ajax 响应后再执行一下取消操作, 把已经完成的请求从 pending 中移除
- return response;
- },error =>{
return { data: { } }; 返回一个空对象, 主要是防止控制台报错
});
同一个请求, 没有完成的请求将被取消
利用这个方法, 一方面可以防止重复点击不同页码导致的表格数据闪烁, 另外可以做实时搜索, 始终获取最新结果.
最后取消重复请求会有些问题. 第二次请求时后台已经接收到了请求. 还是会生成 2 次相同的数据. 下面是对应的处理:
- let pending =[]
- letCancelToken= axios.CancelToken
- let removePending =(config, f)=>{
- let flagUrl = config.url +'&'+ config.method
- if(pending.indexOf(flagUrl)!==-1){
- if(f){
- f()// 执行取消操作
- }else{
- pending.splice(pending.indexOf(flagUrl),1)// 把这条记录从数组中移除
- }
- }else{
- if(f){
- pending.push(flagUrl)
- }
- }
- }
- // http request 拦截器
- HTTP.interceptors.request.use(
- config =>{
- if(config.method ==='post'){
- console.log('我是拦截')
- config.cancelToken =newCancelToken((c)=>{
- removePending(config, c)
- })
- }
- return config
- },
- err =>{
- returnPromise.reject(err)
- })
- // http response 拦截器
- HTTP.interceptors.response.use(
- response =>{
- if(response.config.method ==='post'){
- removePending(response.config)
- }
- return response
- },
- error =>{
- pending =[]
- return{ data:{error: error}}// 返回接口返回的错误信息
- })
第一种适合 tabs, 分页等快速来回点击的情况, 取消之前的请求, 保持最近的一次请求.
第二种适合相同的接口被请求了多次, 只留第一次, 其他的都取消请求.