axios CancelToken 实现对特定请求的拦截,不要所有请求都进行相同的拦截

Posted Himmelbleu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了axios CancelToken 实现对特定请求的拦截,不要所有请求都进行相同的拦截相关的知识,希望对你有一定的参考价值。

前言

一旦给 axios 添加了拦截器,就会对所有的 post、get 等请求进行拦截。但不是所有的请求都需要进行拦截,如公共的请求,即不需要用户登录即可发起请求的 api 我们应当放行。

  1. 通过 axios.interceptors.request.eject(requestId) 清除 request 或者 response 的拦截器。想要再次恢复就需要重新创建拦截器。
  2. 第二种通过 axios.CancelToken.source() 更加灵活地处理需拦截的逻辑,如只需要拦截没有登录的请求,不需要所有请求都需要登录,并可处理本次的错误消息。

axios CancelToken

  1. 创建 axios.CancelToken.source() CancelToken 的实例。
  2. 在拦截器中或者其他任何地方通过 CancelToken 提供的 cancel 函数取消本次请求,并提供错误消息。
import axios from "axios";

const axiosInstance = axios.create(
  baseURL: "http://localhost:9000/api/v1"
);

// 将 cancelSource 挂载到 axiosInstance 实例上
axiosInstance.cancelSource = axios.CancelToken.source();
// isCancel 是判断当前错误是否为主动取消拦截器的错误,同样挂载到 axios 实例上
axiosInstance.isCancel = axios.isCancel;

axiosInstance.interceptors.request.use(
  config => 
    if (!localStorage.getItem("userId")) 
      // 用户没有登陆,停止添加了 cancelToken 的请求,并给出本次请求失败的错误消息
      axiosInstance.cancelSource.cancel("您没有登陆,本次操作取消!");
    
    
    // 其他拦截的业务逻辑,如拦截一次性请求发了很多次等。可见 CancelToken 很灵活

    return config;
  ,
  error => 
    return Promise.reject(error);
  
);

axiosInstance.interceptors.request.use(
  config => 
    return config;
  ,
  error => 
    return Promise.reject(error);
  
);

export  axiosInstance ;

针对特定请求的拦截

  1. 在本次请求中,需要验证用户是否登录,因此在请求配置项中添加 cancelToken: axiosInstance.cancelSource.token
  2. 程序发起请求之后,经过请求的拦截器。
  3. 若没有登陆,取消本次请求,并进入 catch 块,处理错误。
  4. 若登录,不取消本次请求,请求可以完整执行。
export async function setCollection(bodyData) 
  try 
    const  data: completed  = await axiosInstance.post(
      "/set/collection",
      bodyData,
      // 本次请求需要用户登录才可以发出
       cancelToken: axiosInstance.cancelSource.token 
    );
    return completed;
   catch (error) 
    // 判断档次错误是否为因没有登陆(cancelToken)导致的错误
    if (axiosInstance.isCancel(error)) 
      ElMessage.warning(error.message);
     else 
      throw error;
    
  

小结

通过 axios 提供的 CancelToken 可以标识本次请求是否需要经过拦截器中的判断同意通过才可发起。

  1. 在拦截器中,用户没有登录时,通过 CalcenToken 提供的 cancel 取消本次请求。
  2. 在拦截器中,用户没有登陆时,通过 CalcenToken 提供的 cancel 函数传递本次错误的消息。
  3. 给单次的请求中添加一项, cancelToken: axiosInstance.cancelSource.token 配置项,表示本次请求需要验证 cancelToken。

axios 的理解和使用 axios.create(对axios请求进行二次封装) 拦截器 取消请求(axios.CancelToken)

axios 的理解和使用 axios.create(对axios请求进行二次封装) 拦截器 取消请求(axios.CancelToken)

 

 

axios是什么

  1. 前端最流行的 ajax请求库
  2. react/vue官方推荐使用axios发ajax请求
  3. 文档 https://github.com/axios/axios

axios特点

  1. 基于promise的异步ajax请求库
  2. 浏览器端/node端都可以使用
  3. 支持请求/响应拦截器
  4. 支持请求取消
  5. 请求/响应数据转换
  6. 批量发送多个请求

axios常用语法

namvalue
axios(config) 通用/最本质的发任意类型请求的方式
axios(url[,config]) 可以只指定url发get请求
axios.request(config) 等同于axios(config)
axios.get(url[,config]) 发get请求
axios.delete(url[,config]) 发delete请求
axios.post(url[,data,config]) 发post请求
axios.put(url[,data,config]) 发put请求
   
   
axios.defaults.xxx 请求非默认全局配置
axios.interceptors.request.use() 添加请求拦截器
axios.interceptors.response.use() 添加响应拦截器
   
   
axios.create([config]) 创建一个新的axios(他没有下面的功能)
   
   
axios.Cancel() 用于创建取消请求的错误对象
axios.CancelToken() 用于创建取消请求的token对象
axios.isCancel() 是否是一个取消请求的错误
axios.all(promise) 用于批量执行多个异步请求

axios安装

npm install axios
  • 1

vue项目使用
在main.js

import axios from ‘axios‘
Vue.prototype.$ajax = axios
  • 1
  • 2

html 直接导入就行了

<script src="https://cdn.bootcss.com/axios/0.19.0/axios.js"></script>
  • 1

axios简单使用

默认get请求

// 配置默认基本路径
axios.defaults.baseURL = ‘http://localhost:3000‘

// 默认get请求
axios({
	url:"/posts",
	params:{
		id:1
	}
}).then(res=>{
	console.log(res)
},err=>{
    console.log(err)
})

 

 

post

// post请求
axios.post("/posts",{id:1}).then(res=>{
	console.log(res)
},err=>{
    console.log(err)
})

// 或

axios({
	url:"/posts",
	method:‘post‘
	data:{
		id:1
	}
}).then(res=>{
	console.log(res)
},err=>{
    console.log(err)
})

 

put

axios.put("/posts/4",{
      "title": "json-server---1",
      "author": "typicode",
    }).then(res=>{
	console.log(res)
},err=>{
    console.log(err)
})

// 或
axios({
	url:"/posts",
	method:‘put ‘
	data:{
      "title": "json-server---1",
      "author": "typicode",
    }
}).then(res=>{
	console.log(res)
},err=>{
    console.log(err)
})

 

 

delete

axios.delete("/posts/4",{
      "title": "json-server---1",
      "author": "typicode",
    }).then(res=>{
	console.log(res)
},err=>{
    console.log(err)
})

// 或
axios({
	url:"/posts",
	method:‘delete‘
	data:{
		id:1
	}
}).then(res=>{
	console.log(res)
},err=>{
    console.log(err)
})

 

 

axios难点语法

axios.create(config) 对axios请求进行二次封装

  1. 根据指定配置创建一个新的 axios ,也就是每个axios 都有自己的配置
  2. 新的 axios 只是没有 取消请求批量请求 的方法,其它所有语法都是一致的
  3. 为什么要这种语法?
    1. 需求,项目中有部分接口需要的配置与另一部分接口的配置不太一样
    2. 解决:创建2个新的 axios ,每个都有自己的配置,分别对应不同要求的接口请求中

简单使用

const instance = axios.create({
   baseURL:"http://localhost:3000"
})

// 使用instance发请求
instance({
    url:"/posts"
})

// 或
instance.get("/posts")

 

技术图片
同时请求 多个端口号

const instance = axios.create({
    baseURL:"http://localhost:3000"
})

const instance2 = axios.create({
    baseURL:"http://localhost:4000"
})

// 同时请求 端口号 3000 4000

// 使用instance发请求
instance({
    url:"/posts"
})

// 使用instance2发请求
instance2({
    url:"/posts"
})

 

 

axios的处理链流程 拦截器

拦截器简单使用
// 添加请求拦截器
axios.interceptors.request.use(config=>{
	// config 请求配置
    console.log("请求拦截器")
    return config
},err=>{
    return Promise.reject(err)
})  

// 添加响应拦截器
axios.interceptors.response.use(res=>{
	// res 响应结果
    console.log("响应拦截器")
    return res
},err=>{
    return Promise.reject(err)
})  

console.log("开始请求")
axios.get("http://localhost:3000/posts")
.then(res=>{
    console.log("res:",res)
    console.log("请求结束")
})

技术图片

多个拦截器

请求拦截器后添加先执行

// 添加请求拦截器
axios.interceptors.request.use(config=>{
    console.log("请求拦截器")
    return config
},err=>{
    return Promise.reject(err)
})  

axios.interceptors.request.use(config=>{
    console.log("请求拦截器--------2")
    return config
},err=>{
    return Promise.reject(err)
})  

axios.interceptors.request.use(config=>{
    console.log("请求拦截器--------3")
    return config
},err=>{
    return Promise.reject(err)
})  


// 添加响应拦截器
axios.interceptors.response.use(res=>{
    console.log("响应拦截器")
    return res
},err=>{
    return Promise.reject(err)
})  

axios.interceptors.response.use(res=>{
    console.log("响应拦截器---------2")
    return res
},err=>{
    return Promise.reject(err)
}) 

axios.interceptors.response.use(res=>{
    console.log("响应拦截器----------3")
    return res
},err=>{
    return Promise.reject(err)
})

console.log("开始请求")
axios.get("http://localhost:3000/posts")
.then(res=>{
    console.log("res:",res)
    console.log("请求结束")
})

 

 

技术图片

取消请求

1. 基本流程
配置 cancelToken 对象
缓存用于取消请求的 cancel 函数
在后面特定时机调用 cancel 函数取消请求
在错误回调中判断如果 error 是cancel ,做相应处理
  • 1
  • 2
  • 3
  • 4
2. 实现功能

node运行server.js
安装node和express (npm install express)

var http = require("http");

var express = require("express")
// var server = http.createServer();
var app = express()

// node跨域设置
app.all("*",function(req,res,next){
    //设置允许跨域的域名,*代表允许任意域名跨域
    res.header("Access-Control-Allow-Origin","*");
    //允许的header类型
    res.header("Access-Control-Allow-Headers","content-type");
    //跨域允许的请求方式 
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == ‘options‘)
        res.send(200);  //让options尝试请求快速结束
    else
        next();
})


app.get(‘/‘,function(res,req){
    console.log("获取客户端请求",res);
    // 延迟响应 方便测试取消接口
    setTimeout(function(){
        req.end("延迟响应 方便测试取消接口"); //响应客户数据
    },5000)
    
})

app.listen(4000,function(){
    console.log("服务器启动成功,可以通过 http://127.0.0.1:4000 进行访问")
})

 

 

在cmd窗口

node server.js
  • 1

调用接口测试
axios.isCancel(err) //判断错误是否 是取消请求导致的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/axios/0.19.0/axios.js"></script>
</head>
<body>
    <script>
        let cancel;

        // axios({
        //     url:"http://localhost:4000",
        //     cancelToken:new axios.CancelToken(function(c){
        //         cancel = c
        //     })
        // })
        // 或

        axios.get("http://localhost:4000",{
            cancelToken:new axios.CancelToken(function(c){
                // c 用于取消当前请求的函数
                cancel = c
            })
        })
        .then(res=>{
            console.log("res:",res)
            cancel = null //请求完成,清空cancel
        },err=>{
            cancel = null 
            if(err.constructor.name === ‘Cancel‘){ //是取消请求导致的errer
                console.log("取消请求导致error:",err)
            }else{
                console.log("err:",err)
            }
			// 或
            // axios.isCancel(err) //判断错误是否 是取消请求导致的
        });

        setTimeout(function(){
            if(typeof(cancel) === ‘function‘){
                cancel(‘强制取消了请求‘)
            }else{
                console.log("没有可取消的请求")
            }
        },2000)
    </script>
</body>
</html>

 

 

正常请求
技术图片
取消接口

技术图片

在 请求拦截器里面统一添加取消请求
axios.interceptors.request.use(res=>{
  	res[‘cancelToken‘] = new axios.CancelToken(function(c){
        cancel = c
    })
    return res
},err=>{
    return Promise.reject(err)
})

 

 

在 响应拦截器里面统一添加 处理取消请求
axios.interceptors.response.use(res=>{
  
    return res
},err=>{
	if(axios.isCancel(err)){
		// 中断promise链接
		return new Promise(()=>{})
	}else{
		// 把错误继续向下传递
    	return Promise.reject(err)
	}
})

 

 

代码简化 实现上一个接口还未响应 下一个接口开始请求,把上一个接口取消
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/axios/0.19.0/axios.js"></script>
</head>
<body>
    <script>
        let cancel;

        axios.interceptors.request.use(config=>{
            // 实现上一个接口还未响应  下一个接口开始请求,把上一个接口取消
            if(typeof(cancel) === ‘function‘){
                cancel(‘强制取消了请求‘)
            }
            config[‘cancelToken‘] = new axios.CancelToken(function(c){
                cancel = c
            })
            return config
        },err=>{
            return Promise.reject(err)
        }) 

        axios.interceptors.response.use(res=>{
            cancel = null 
            return res
        },err=>{
            cancel = null 
            if(axios.isCancel(err)){
                console.log("取消上一个请求")
                // 中断promise链接
                return new Promise(()=>{})
            }else{
                // 把错误继续向下传递
                return Promise.reject(err)
            }
        })  
        function request(){
            axios.get("http://localhost:4000")
            .then(res=>{
                console.log("res:",res)
            },err=>{
                console.log("err:",err)
            });
        }
        
        request()
        request()
    </script>
</body>
</html>

 

 

技术图片

 

以上是关于axios CancelToken 实现对特定请求的拦截,不要所有请求都进行相同的拦截的主要内容,如果未能解决你的问题,请参考以下文章

如何取消axios请求

这次终于弄懂Axios是如何中断请求了

这次终于弄懂Axios是如何中断请求了

这次终于弄懂Axios是如何中断请求了

这次终于弄懂Axios是如何中断请求了

vue axios拦截器常用之重复请求取消