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. 否则,将当前请求对象更新到缓存中,允许请求继续发送。
相关推荐
清岚_lxn2 小时前
原生SSE实现AI智能问答+Vue3前端打字机流效果
前端·javascript·人工智能·vue·ai问答
ZoeLandia3 小时前
Element UI 设置 el-table-column 宽度 width 为百分比无效
前端·ui·element-ui
橘子味的冰淇淋~3 小时前
解决 vite.config.ts 引入scss 预处理报错
前端·vue·scss
萌萌哒草头将军4 小时前
💎这么做,cursor 生成的代码更懂你!💎
javascript·visual studio code·cursor
小小小小宇5 小时前
V8 引擎垃圾回收机制详解
前端
lauo5 小时前
智体知识库:ai-docs对分布式智体编程语言Poplang和javascript的语法的比较(知识库问答)
开发语言·前端·javascript·分布式·机器人·开源
拉不动的猪6 小时前
设计模式之------单例模式
前端·javascript·面试
一袋米扛几楼986 小时前
【React框架】什么是 Vite?如何使用vite自动生成react的目录?
前端·react.js·前端框架
Alt.96 小时前
SpringMVC基础二(RestFul、接收数据、视图跳转)
java·开发语言·前端·mvc
lorogy6 小时前
【VSCode配置】运行springboot项目和vue项目
vue.js·spring boot·vscode