国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

使用Redis控制表單重復(fù)提交控制接口訪問頻率

這篇具有很好參考價值的文章主要介紹了使用Redis控制表單重復(fù)提交控制接口訪問頻率。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

場景一:控制表單重復(fù)提交

防重提交有很多方案,從前端的按鈕置灰,到后端synchronize鎖、Lock鎖、借助Redis語法實現(xiàn)簡單鎖、Redis+Lua分布式鎖、Redisson分布式鎖,再到DB的悲觀鎖、樂觀鎖、借助表唯一索引等等都可以實現(xiàn)防重提交,以保證數(shù)據(jù)的安全性。
這篇文章我們介紹其中一種方案–借助Redis語法實現(xiàn)簡單鎖,最終實現(xiàn)防重提交。

背景:

我們項目中,為了控制表單重復(fù)提交問題,會在點擊頁面按鈕(向后端發(fā)起業(yè)務(wù)請求)后就會置灰按鈕,直到后端響應(yīng)后解除按鈕置灰。通過按鈕置灰來防止重啟提交問題。但Postman、Jmeter和其他服務(wù)調(diào)用(繞過前端頁面)呢?所以后端接口也要根據(jù)控制表單重復(fù)提交的問題。

后端代碼可以在2個位置做控制:
一是放在gateway網(wǎng)關(guān)做
好處是只在一個地方加上控制代碼,就可以控制所有接口的重復(fù)提交問題。壞處是控制的范圍太廣(比如查詢接口無需控制,控制了反而多余)、定義重復(fù)提交的時間段不能靈活調(diào)整。
二是放在AOP切面做
好處是只有需要的地方才會被控制(哪里需要引用一下自定義注解即可),另外也能靈活調(diào)整定義重復(fù)提交的時間段(自定義注解里定義時間字段開放給使用者填寫)。壞處是每個需要控制的地方都要加注解,會有侵入性和一定的工作量。

實現(xiàn)代碼

1、添加自定義注解

package com.xxx.annotations;

import java.lang.annotation.*;

/**
 * 自定義注解防止表單重復(fù)提交
 *
 * @Author WANGLINGQIANG
 * @Date 2023/9/6 10:11
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit {

    /**
     * 過期時間,單位毫秒
     */
    long expireTime() default 500L;

}

2、添加AOP切面

package com.xxx.aop;

import com.xxx.annotations.RepeatSubmit;
import com.xxx.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 防止表單重復(fù)提交切面
 *
 * @Author WANGLINGQIANG
 * @Date 2023/9/6 10:13
 */
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect {
    private static final String KEY_PREFIX = "repeat_submit:";
    @Resource
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.xxx.annotations.RepeatSubmit)")
    public void repeatSubmit() {}

    @Around("repeatSubmit()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    	//joinPoint獲取方法對象
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        //獲取方法上的@RepeatSubmit注解
        RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
        //獲取HttpServletRequest對象,以獲取請求uri
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String uri = request.getRequestURI();
        //拼接Redis的key,這里只是簡單根據(jù)uri來判斷是否重復(fù)提交??梢愿鶕?jù)自己業(yè)務(wù)調(diào)整,比如根據(jù)用戶id或者請求token等
        String cacheKey = KEY_PREFIX.concat(uri);
        Boolean flag = null;
        try {
            //借助setIfAbsent(),key不存在才能設(shè)值成功
            flag = redisTemplate.opsForValue().setIfAbsent(cacheKey, "", annotation.expireTime(), TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            //如果Redis不可用,則打印日志記錄,但依然對請求放行
            log.error("", e);
            return joinPoint.proceed();
        }
        //Redis可用的情況,如果flag=true說明單位時間內(nèi)這是第一次請求,放行
        if (flag) {
            return joinPoint.proceed();
        } else {
            //進(jìn)入else說明單位時間內(nèi)進(jìn)行了多次請求,則攔截請求并提示稍后重試
            throw new ServiceException("系統(tǒng)繁忙,請稍后重試");
        }
    }
}

這里利用redisTemplate的setIfAbsent()實現(xiàn)的,如果存在就不能set成功,set的同時設(shè)置過期時間,可以是用使用默認(rèn),也可以自己根據(jù)業(yè)務(wù)調(diào)整。
另外,cacheKey的定義,也可以根據(jù)自己的需要去調(diào)整,比如根據(jù)當(dāng)前登錄用戶的userId、當(dāng)前登錄的token等。

3、使用

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

	@RepeatSubmit
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysUser user) {
    	//....
    }


場景二:控制接口調(diào)用頻率

背景:

忘記密碼后通過發(fā)送手機(jī)驗證碼找回密碼的場景。因為每發(fā)一條短信都需要收費,所以要控制發(fā)短信的頻率。比如,同一個手機(jī)號在3分鐘內(nèi)只能發(fā)送3次短信,超過3次后則提示用戶“短信發(fā)送過于頻繁,請10分鐘后再試”。


實現(xiàn)代碼

@Slf4j
@RestController
@RequestMapping("/sms")
public class SmsController {
    @Resource
    private ISmsService smsService;
    @Resource
    public RedisTemplate redisTemplate;

    @PostMapping("/sendValidCode")
    public Result sendValidCode(@RequestBody @Valid SmsDTO smsDTO) {
        //驗證手機(jī)號格式
        checkPhoneNumber(smsDTO.getPhoneNumber());
        
        //...其他驗證
        
		//拼接Redis的key(key為手機(jī)號,以控制一個手機(jī)號有限時間內(nèi)容發(fā)送的次數(shù))
        String cacheKey = "sms:code:resetPwd:"+smsDTO.getPhoneNumber();
        //驗證發(fā)送短信次數(shù),超過則攔截(閾值是3次,超時時間是3分鐘,重試時間是10分鐘)
        checkSendCount(cacheKey, THRESHOLD, TIMEOUT, RETRY_TIME);
        return smsService.sendMsg(smsDTO);
    }
    
    /**
     * 驗證發(fā)送短信次數(shù),超過則攔截
     * 該方法用lua腳本替換實現(xiàn)更好
     */
    private void checkSendCount(String cacheKey, Long threshold, Long timeout, String retryTime) {
   		//首先進(jìn)方法就先+1
        Long count = redisTemplate.opsForValue().increment(cacheKey);
        //然后比較次數(shù),是否超過閾值
        if (count > threshold) {
            //超過則設(shè)置過期時間為10分鐘,并提示10分鐘后重試
            redisTemplate.expire(cacheKey, 10L, TimeUnit.MINUTES);
            throw new ServiceException("短信發(fā)送過于頻繁,請" + retryTime + "分鐘后再試");
        } else {
            //沒超過3次,則累加上這一次
            redisTemplate.expire(cacheKey, timeout, TimeUnit.MINUTES);
        }
    }

}

本章完結(jié)。

文章來源地址http://www.zghlxwxcb.cn/news/detail-697475.html

到了這里,關(guān)于使用Redis控制表單重復(fù)提交控制接口訪問頻率的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • springboot3使用自定義注解+AOP+redis優(yōu)雅實現(xiàn)防重復(fù)提交

    springboot3使用自定義注解+AOP+redis優(yōu)雅實現(xiàn)防重復(fù)提交

    ? ??個人主頁:? ? ?蒾酒 ?? 系列專欄 :《spring boot實戰(zhàn)》 ?? 山高路遠(yuǎn),行路漫漫,終有歸途 目錄 寫在前面 實現(xiàn)思路 實現(xiàn)步驟 1.定義防重復(fù)提交注解 2.編寫一個切面去發(fā)現(xiàn)該注解然后執(zhí)行防重復(fù)提交邏輯 3.測試 依賴條件 1.接口上標(biāo)記防重復(fù)提交注解 2.接口測試 寫在最

    2024年04月11日
    瀏覽(21)
  • HTML5中form表單防止重復(fù)提交的兩種方法

    form表單重復(fù)提交是在多用戶Web應(yīng)用中最常見、帶來很多麻煩的一個問題。有很多的應(yīng)用場景都會遇到重復(fù)提交問題 (1)點擊提交按鈕兩次。 (2)點擊刷新按鈕。 (3)使用瀏覽器后退按鈕重復(fù)之前的操作 導(dǎo)致重復(fù)提交表單。 (4)瀏覽器重復(fù)的HTTP請求。 (5)用戶提交表單時可能因為網(wǎng)

    2024年01月22日
    瀏覽(44)
  • 前端如何防止接口重復(fù)提交

    接口重復(fù)提交指的是在網(wǎng)絡(luò)通信中,同一個請求被客戶端多次發(fā)送到服務(wù)器端的情況。這種情況可能由于多種原因?qū)е?,例如用戶在等待期間多次點擊提交按鈕、網(wǎng)絡(luò)超時后客戶端重新發(fā)送請求、客戶端發(fā)送的請求在網(wǎng)絡(luò)傳輸過程中出現(xiàn)重復(fù)等。 接口重復(fù)提交可能會導(dǎo)致多種

    2024年04月22日
    瀏覽(28)
  • SpringBoot 整合redis + Aop防止重復(fù)提交 (簡易)

    SpringBoot 整合redis + Aop防止重復(fù)提交 (簡易)

    redis下載 解壓 安裝 看一下就會有 ?進(jìn)入redis-6.0.8下的src目錄 (? src?目錄下有編譯后的 redis 服務(wù)程序 redis-server,還有用于測試的客戶端程序 redis-cli:) 然后啟動 redis默認(rèn)端口號 6379,建議更改。redis.conf是配置文件在? 與src是同級目錄。 要遠(yuǎn)程? #去掉保護(hù)模式,注釋掉bi

    2024年02月12日
    瀏覽(31)
  • SpringBoot限制接口訪問頻率 - 這些錯誤千萬不能犯

    最近在基于SpringBoot做一個面向普通用戶的系統(tǒng),為了保證系統(tǒng)的穩(wěn)定性,防止被惡意攻擊,我想控制用戶訪問每個接口的頻率。為了實現(xiàn)這個功能,可以設(shè)計一個annotation,然后借助AOP在調(diào)用方法之前檢查當(dāng)前ip的訪問頻率,如果超過設(shè)定頻率,直接返回錯誤信息。 在開始介

    2024年02月05日
    瀏覽(17)
  • springboot實現(xiàn)后端防重復(fù)提交(AOP+redis分布式鎖)單機(jī)情況下

    springboot實現(xiàn)后端防重復(fù)提交(AOP+redis分布式鎖)單機(jī)情況下

    為什么要實現(xiàn)這個功能呢,可能用戶在提交一份數(shù)據(jù)后,可能因為網(wǎng)絡(luò)的原因、處理數(shù)據(jù)的速度慢等原因?qū)е马撁鏇]有及時將用戶剛提交數(shù)據(jù)的后臺處理結(jié)果展示給用戶,這時用戶可能會進(jìn)行如下操作: 1秒內(nèi)連續(xù)點擊提交按鈕,導(dǎo)致重復(fù)提交表單。 使用瀏覽器后退按鈕重復(fù)之

    2024年02月08日
    瀏覽(26)
  • 06_HTML_表單提交的細(xì)節(jié)(submit提交按鈕的使用細(xì)節(jié))

    06_HTML_表單提交的細(xì)節(jié)(submit提交按鈕的使用細(xì)節(jié))

    示例 運行效果 點擊提交后,會跳轉(zhuǎn)至form標(biāo)簽中action屬性所對應(yīng)的鏈接,并將表單中的內(nèi)容發(fā)給服務(wù)器。 (這里使用http://localhost:8080 地址演示提高效率) 隨意填寫表單內(nèi)的內(nèi)容,然后點擊\\\"點擊提交\\\" 成功跳轉(zhuǎn),并接收數(shù)據(jù) 這里我們分析地址: 這里會發(fā)現(xiàn):?后面都是元素標(biāo)

    2024年02月01日
    瀏覽(18)
  • 使用UE4 HttpRequest提交多表單

    大部分HTTP庫都是支持直接設(shè)置多表單字段的,但UE4的HttpRequest比較慘,只能用SetContent設(shè)置整個的TArrayuint8作為請求體,所以想要傳多表單就要自己拼。 首先設(shè)置Header,Content-Type設(shè)置為多表單,并設(shè)置boundary: boundary想設(shè)什么都行,但要和后面用的統(tǒng)一。 然后拼請求體的數(shù)據(jù)字

    2024年02月07日
    瀏覽(28)
  • 使用postman提交post方式的表單請求

    使用postman提交post方式的表單請求

    這里請求路徑是測試數(shù)據(jù)庫的,本地調(diào)試的話要換成自己的host和ip

    2024年02月12日
    瀏覽(25)
  • Vue表單提交正則表達(dá)式驗證使用案例

    一、驗證表單用法 1、表單布局及變量定義 2、定義表單中用到的實例、變量、交互dto等 3、驗證規(guī)則表達(dá)式 說明: 1、sendRules?是表單使用的驗證規(guī)則對象 2、屬性?xxxNo?是具體校驗?zāi)莻€屬性字段 3、屬性 required?非空校驗 4、屬性?message?提示字樣 5、屬性?trigger?觸發(fā)事件 6、

    2024年02月16日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包