Spring Boot 如何使用 Redis 進(jìn)行 API 防刷限流?

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
某api被各式各樣系統(tǒng)廣泛調(diào)用,嚴(yán)重消耗網(wǎng)絡(luò)、內(nèi)存等資源,需要合理限流
淘寶獲取ip所在城市接口、微信公眾號識別微信用戶等開發(fā)接口,免費(fèi)提供給用戶時需要限流,更具有實時性和準(zhǔn)確性的接口需要付費(fèi)。
API 限流實戰(zhàn)
首先我們編寫注解類AccessLimit,使用注解方式在方法上限流更優(yōu)雅更方便!Spring Boot 如何集成 Redis 請點(diǎn)擊這里進(jìn)行閱讀。
三個參數(shù)分別代表有效時間、最大訪問次數(shù)、是否需要登錄,可以理解為 seconds 內(nèi)最多訪問 maxCount 次。
import?java.lang.annotation.ElementType;
import?java.lang.annotation.Retention;
import?java.lang.annotation.RetentionPolicy;
import?java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public?@interface?AccessLimit?{
????int?seconds();
????int?maxCount();
????boolean?needLogin()?default?true;
}
限流的思路:
通過路徑:ip的作為key,訪問次數(shù)為value的方式對某一用戶的某一請求進(jìn)行唯一標(biāo)識
每次訪問的時候判斷
key是否存在,是否count超過了限制的訪問次數(shù)若訪問超出限制,則應(yīng)
response返回msg:請求過于頻繁給前端予以展示
import?org.springframework.beans.factory.annotation.Autowired;
import?org.springframework.stereotype.Component;
import?org.springframework.web.method.HandlerMethod;
import?org.springframework.web.servlet.HandlerInterceptor;
import?javax.servlet.http.HttpServletRequest;
import?javax.servlet.http.HttpServletResponse;
@Component
public?class?AccessLimtInterceptor?implements?HandlerInterceptor?{
????@Autowired
????private?RedisService?redisService;
????@Override
????public?boolean?preHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler)?throws?Exception?{
????????if?(handler?instanceof?HandlerMethod)?{
????????????HandlerMethod?hm?=?(HandlerMethod)?handler;
????????????AccessLimit?accessLimit?=?hm.getMethodAnnotation(AccessLimit.class);
????????????if?(null?==?accessLimit)?{
????????????????return?true;
????????????}
????????????int?seconds?=?accessLimit.seconds();
????????????int?maxCount?=?accessLimit.maxCount();
????????????boolean?needLogin?=?accessLimit.needLogin();
????????????if?(needLogin)?{
????????????????//判斷是否登錄
????????????}
????????????String?key?=?request.getContextPath()?+?":"?+?request.getServletPath()?+?":"?+?ip?;
????????????Integer?count?=?redisService.get(key);
????????????if?(null?==?count?||?-1?==?count)?{
????????????????redisService.set(key,?1);
????????????????redisService.expire(seconds);
????????????????return?true;
????????????}
????????????if?(count?????????????????redisService.inCr(key);
????????????????return?true;
????????????}
????????????if?(count?>=?maxCount)?{
//????????????????response?返回?json?請求過于頻繁請稍后再試
????????????????return?false;
????????????}
????????}
????????return?true;
????}
}
注冊攔截器并配置攔截路徑和不攔截路徑:
import?org.springframework.beans.factory.annotation.Autowired;
import?org.springframework.context.annotation.Configuration;
import?org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import?org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//?extends?WebMvcConfigurerAdapter?已經(jīng)廢棄,java?8開始直接繼承就可以
@Configuration
public?class?IntercepterConfig??implements?WebMvcConfigurer?{
????@Autowired
????private?AccessLimtInterceptor?accessLimtInterceptor;
????@Override
????public?void?addInterceptors(InterceptorRegistry?registry)?{
????????registry.addInterceptor(accessLimtInterceptor)
????????????????.addPathPatterns("/攔截路徑")
????????????????.excludePathPatterns("/不被攔截路徑?通常為登錄注冊或者首頁");
????}
}
在Controller層的方法上直接可以使用注解@AccessLimit
import?org.springframework.web.bind.annotation.GetMapping;
import?org.springframework.web.bind.annotation.RequestMapping;
import?org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("test")
public?class?TestControler?{
????@GetMapping("accessLimit")
????@AccessLimit(seconds?=?3,?maxCount?=?10)
????public?String?testAccessLimit()?{
????????//xxxx
????????return?"";
????}
}
作者:海向
出處:cnblogs.com/haixiang/p/12012728.html






關(guān)注Java技術(shù)棧看更多干貨
戳原文,獲取更多福利!評論
圖片
表情
