目錄
前言
什么是限流?
實現限流
創建一個注解類
接著創建一個切面類
前言
在項目中,對于接口的限流,是任何項目都必不可少的一部分,主要是為了防止用戶頻繁的發送請求,對服務器造成壓力。
另外一點就是防止外來攻擊,對服務器也會造成壓力,所以才衍生出了需要對接口進行限流訪問的次數
什么是限流?
限流通俗來講就是限制流量大小,這里的流量并不是指我們平常手機上的流量,這里的流量指的是,用戶每一次刷新網頁時對服務器發送一次請求,就是一次流量。
我們通過限流,來防止用戶過多刷新網頁,平常我們也會看到一些網頁,發送驗證碼過多次數,他就會提示你請稍后再發送。
實現限流
我們這里使用springBoot的AOP切面編程,來對接口進行限流操作
創建一個注解類
我們先創建一個注解類,因為對于AOP切面編程來說,集成注解模式是最好的解決方案
這里定義了兩個參數
一個允許被訪問的次數,是自定義的
還有一個默認的60秒,是在一段時間內進行限流多少次
package com.sxy.recordnetwork.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 設置訪問次數限制的注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {int count(); // 允許被訪問的次數int seconds() default 60; // 時間范圍,秒為單位,表示在60秒內訪問的次數}
接著創建一個切面類
主要的邏輯就是,在標注了這個注解類AccessLimit的方法上執行的AOP切面,在方法執行之前
我們通過JoinPoint對象,獲取到目標方法名,以方法名作為唯一的key
接著獲取注解里的參數,為次數和時間
key為方法名:值為訪問次數
對它進行一定的判斷,然后每一次訪問這個接口都會調用decrement這個方法,對key對應的值(訪問次數)進行自減操作
package com.sxy.recordnetwork.aspect;import com.sxy.recordnetwork.Exception.Son.ApiRateLimitExceedException;
import com.sxy.recordnetwork.annotation.AccessLimit;
import com.sxy.recordnetwork.enumeration.Constants;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** 設置訪問次數限制的AOP切面*/
@Aspect
@Component
@Slf4j
public class AccessLimitAspect {@Autowired // redisprivate RedisTemplate redisTemplate;// 添加一個前置通知,在方法執行之前執行 切入點為滿足添加了這個AccessLimit注解的方法@Before("@annotation(accessLimit)")public void AccessLimitBefore(JoinPoint joinPoint, AccessLimit accessLimit) {// 獲取注解的屬性// 通過joinPoint獲取目標方法名String methodName = joinPoint.getSignature().getName();// 設置一下redis的訪問ValueOperations valueOperations = redisTemplate.opsForValue();// 獲取注解屬性Integer count = accessLimit.count(); // 訪問次數int seconds = accessLimit.seconds(); // 在一定時間內// 設置初始值,如果不存在則設置,存在則不設置,返回一個boolean,設置了就為true,否則是falseBoolean isNew = valueOperations.setIfAbsent(methodName, count - 1, seconds, TimeUnit.SECONDS);// 判斷是舊的keyif (!isNew) {// 如果鍵存在,獲取當前值并且遞減Integer currentCount = (Integer) valueOperations.get(methodName);// 次數小于等于0就是訪問次數超出限制if (currentCount != null && currentCount <= 0) {throw new ApiRateLimitExceedException(Constants.FREQUENT_VISITS.getValue());} else {// 遞減valueOperations.decrement(methodName, 1);}}}
}
在控制層就這么添加注解,count就是訪問的次數
這樣就實現了一個簡單的對接口進行限流
以上就是今天分享的內容,對接口進行限流,如有問題,歡迎在下方評論區留言,感謝大家的支持,給個三連唄~🍒
歡迎大家關注我的微信公眾號,里面分享了更多的開發技巧