ruoyi-vue若依前端是如何防止接口重复请求

防止接口重复请求是为了避免用户在短时间内多次点击同一个按钮,导致后端接口被多次调用,引发数据异常或性能问题。

之前的文章介绍过后端如何防止接口重复请求,这篇文章介绍一下前端如何防止接口重复提交。

按钮禁用

用户点击按钮后立即将按钮设置为禁用状态,待接口返回结果或一段时间后再恢复按钮可用。这样可以有效防止用户在请求未完成时重复点击。

javascript 复制代码
const submitForm = () => {
       if (!buttonDisabled) {
         buttonDisabled = true;
         axios.post('/api/submit', data)
           .then(response => {
             // 请求成功
           })
           .catch(error => {
             // 错误处理
           })
           .finally(() => {
             // 恢复按钮状态
             buttonDisabled = false;
           });
       }
     }

请求拦截器

以下是若依源码:

javascript 复制代码
// request拦截器
service.interceptors.request.use(config => {
  // 是否需要设置 token
  const isToken = (config.headers || {}).isToken === false
  // 是否需要防止数据重复提交
  const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
  if (getToken() && !isToken) {
    config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
  }
  // get请求映射params参数
  if (config.method === 'get' && config.params) {
    let url = config.url + '?' + tansParams(config.params);
    url = url.slice(0, -1);
    config.params = {};
    config.url = url;
  }
  if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
    const requestObj = {
      url: config.url,
      data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
      time: new Date().getTime()
    }
    const sessionObj = cache.session.getJSON('sessionObj')
    if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
      cache.session.setJSON('sessionObj', requestObj)
    } else {
      const s_url = sessionObj.url;                // 请求地址
      const s_data = sessionObj.data;              // 请求数据
      const s_time = sessionObj.time;              // 请求时间
      const interval = 1000;                       // 间隔时间(ms),小于此时间视为重复提交
      if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
        const message = '数据正在处理,请勿重复提交';
        console.warn(`[${s_url}]: ` + message)
        return Promise.reject(new Error(message))
      } else {
        cache.session.setJSON('sessionObj', requestObj)
      }
    }
  }
  return config
}, error => {
    Promise.reject(error)
})

这段代码是一个请求拦截器 ,用于拦截发送的HTTP请求,并对请求进行一些预处理操作,主要包括Token注入防止重复提交的功能。以下是代码的具体作用:

1. Token设置

js 复制代码
const isToken = (config.headers || {}).isToken === false;
if (getToken() && !isToken) {
  config.headers['Authorization'] = 'Bearer ' + getToken(); 
}
  • 作用 :检查当前请求是否需要携带Token。通过config.headers.isToken字段决定,若isTokenfalse,表示不需要携带Token,否则会将Authorization头设置为带有Bearer前缀的Token。
  • 逻辑getToken()用于获取存储的Token(比如从cookie或localStorage中),并在请求头中注入Authorization,这样后端能够识别用户身份。

2. GET请求参数处理

js 复制代码
if (config.method === 'get' && config.params) {
  let url = config.url + '?' + tansParams(config.params);
  url = url.slice(0, -1);
  config.params = {};
  config.url = url;
}
  • 作用 :对于GET请求,将params参数序列化并拼接到URL中。
  • 逻辑 :如果请求是GET方法,并且存在params参数,那么它会将这些参数通过tansParams方法(通常是将参数对象转为key=value形式的字符串)拼接到URL后面。最后清空config.params,并将新的URL赋值给config.url

3. 防止重复提交

js 复制代码
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
  const requestObj = {
    url: config.url,
    data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
    time: new Date().getTime()
  }
  const sessionObj = cache.session.getJSON('sessionObj');
  if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
    cache.session.setJSON('sessionObj', requestObj);
  } else {
    const s_url = sessionObj.url;
    const s_data = sessionObj.data;
    const s_time = sessionObj.time;
    const interval = 1000;
    if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
      const message = '数据正在处理,请勿重复提交';
      console.warn(`[${s_url}]: ` + message);
      return Promise.reject(new Error(message));
    } else {
      cache.session.setJSON('sessionObj', requestObj);
    }
  }
}
  • 作用:用于防止短时间内重复提交相同的POST或PUT请求。
  • 逻辑
    1. 通过检查config.headers.repeatSubmit字段判断是否启用防重复提交(false表示不启用防重)。
    2. 对于需要防止重复提交的请求(POST或PUT方法),会将请求的urldata和当前时间time封装为requestObj对象。
    3. 读取会话缓存中的上一次请求对象(sessionObj),如果不存在,则将当前请求对象保存到会话缓存中。
    4. 如果上一次请求的urldata和当前请求相同,且两次请求时间间隔小于1秒钟(interval = 1000),则视为重复提交,拦截请求并返回错误信息。
    5. 否则,将当前请求对象更新到缓存中,允许请求继续发送。
相关推荐
F-2H7 分钟前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
苹果酱056710 分钟前
「Mysql优化大师一」mysql服务性能剖析工具
java·vue.js·spring boot·mysql·课程设计
gqkmiss43 分钟前
Chrome 浏览器插件获取网页 iframe 中的 window 对象
前端·chrome·iframe·postmessage·chrome 插件
m0_748247553 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255023 小时前
前端常用算法集合
前端·算法
真的很上进4 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203984 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2344 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1235 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~5 小时前
npm error code ETIMEDOUT
前端·npm·node.js