
API接口防刷
1.缓解服务器压力
接口频繁,可能 1 秒上千次,限制非正常访问可以缓解服务器压力。
2.节约运营成本
短信接口被请求一次,会触发几分钱的运营商费用。
······
发布日期:2021-05-08 09:46:13
浏览次数:25
分类:原创文章
本文共 7425 字,大约阅读时间需要 24 分钟。
API接口防刷
1.缓解服务器压力
接口频繁,可能 1 秒上千次,限制非正常访问可以缓解服务器压力。
2.节约运营成本
短信接口被请求一次,会触发几分钱的运营商费用。
······
AccessLimit注解
import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.METHOD;import static java.lang.annotation.RetentionPolicy.RUNTIME;@Retention(RUNTIME)@Target(METHOD)public @interface AccessLimit { int seconds(); int maxCount();}
限制访问拦截器
** * 防刷拦截器 */@Componentpublic class AccessLimitInterceptor 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 accessLimit = hm.getMethodAnnotation(AccessLimit.class); if(accessLimit == null){ return true; } int seconds = accessLimit.seconds(); int maxCount = accessLimit.maxCount(); String uri = request.getRequestURI(); //这里简单用用户名代替,建议用通过校验的token String token = "username"; String key = token+uri; //从redis中获取用户访问的次数 Integer count = redisService.getString(key,Integer.class); if(count == null){ //第一次访问 redisService.setString(key,"1", seconds, TimeUnit.SECONDS); }else if(count < maxCount){ //加1 redisService.incr(key); }else{ //超出访问次数 render(response,CodeMsg.ACCESS_LIMIT_REACHED); return false; } } return true; } private void render(HttpServletResponse response, CodeMsg cm) throws Exception { response.setContentType("application/json;charset=UTF-8"); OutputStream out = response.getOutputStream(); String str = JSON.toJSONString(Result.codeMsg(cm)); out.write(str.getBytes("UTF-8")); out.flush(); out.close(); }}
拦截器注册
import com.example.book.interceptor.AccessLimitInterceptor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configurationpublic class InterceptorConfig extends WebMvcConfigurationSupport { @Bean public AccessLimitInterceptor getFangshuaInterceptor(){ return new AccessLimitInterceptor(); } @Override protected void addInterceptors(InterceptorRegistry registry) { // registry.addInterceptor(getFangshuaInterceptor()).addPathPatterns("/**"); registry.addInterceptor(getFangshuaInterceptor()); super.addInterceptors(registry); }}
Controller添加AccessLimit 注解
import com.example.book.annotation.AccessLimit;import com.example.book.result.Result;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;import java.util.Map;@RestControllerpublic class BookController { @AccessLimit(seconds=5, maxCount=5) @GetMapping("/book") public Result book(){ Map map = new HashMap<>(); map.put("bookName","hello world"); map.put("author","god"); return Result.success(map); }}
redis简单操作
RedisService 接口
import java.util.concurrent.TimeUnit;public interface RedisService { void setString(String key, String value); void setString(String key, String value, long timeOut); void setString(String key, String value, long timeOut, TimeUnit timeUnit); String getString(String key); <T> T getString(String key, Class<T> clazz); void incr(String key);}
RedisService 实现类
import com.alibaba.fastjson.JSON;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.stereotype.Component;import javax.annotation.Resource;import java.util.concurrent.TimeUnit;@Componentpublic class RedisServiceImpl implements RedisService { @Resource private StringRedisTemplate stringRedisTemplate; /** * 设置key * @param key key * @param value value */ public void setString(String key, String value) { ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue(); valueOperations.set(key, value); } /** * 设置key * @param key * @param value * @param timeOut */ public void setString(String key, String value, long timeOut) { ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue(); valueOperations.set(key, value, timeOut); } /** * 设置key * @param key * @param value * @param timeOut * @param timeUnit */ public void setString(String key, String value, long timeOut, TimeUnit timeUnit) { ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue(); valueOperations.set(key, value, timeOut, timeUnit); } /** * 获取key * @param key key * @return */ public String getString(String key) { return stringRedisTemplate.opsForValue().get(key); } /** * 返回指定类型数据 * @param key * @param clazz * @param <T> * @return */ public <T> T getString(String key, Class<T> clazz) { String jsonValue = stringRedisTemplate.opsForValue().get(key); if(null == jsonValue){ return null; } return JSON.parseObject(jsonValue, clazz); } /** * 加1 * @param key */ @Override public void incr(String key) { stringRedisTemplate.opsForValue().increment(key); }}
简化版统一返回
返回enum
public enum CodeMsg { SUCCESS(200, "成功"), ERROR(500, "服务器异常"), ACCESS_LIMIT_REACHED(403,"已达到访问限制"); private int code; private String msg; CodeMsg(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; }}
返回实体
public class Result<T> { private int code; private String msg; private T data; private Result() { } protected Result(int code, String msg) { this.code = code; this.msg = msg; } protected Result(CodeMsg cm) { this.code = cm.getCode(); this.msg = cm.getMsg(); } protected Result(CodeMsg cm, T data) { this.code = cm.getCode(); this.msg = cm.getMsg(); this.data = data; } public static <T> Result success(T data) { return new Result(CodeMsg.SUCCESS, data); } public static Result codeMsg(CodeMsg cm) { return new Result(cm); } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; }}
发表评论
最新留言
关注你微信了!
[***.104.42.241]2025年03月29日 22时59分01秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
使用QT实现一个简单的登陆对话框(纯代码实现C++)
2019-03-05
QT :warning LNK4042: 对象被多次指定;已忽略多余的指定
2019-03-05
GLFW 源码 下载-编译-使用/GLAD配置
2019-03-05
针对单个网站的渗透思路
2019-03-05
Typescript 学习笔记六:接口
2019-03-05
02、MySQL—数据库基本操作
2019-03-05
OpenJDK1.8.0 源码解析————HashMap的实现(一)
2019-03-05
MySQL-时区导致的时间前后端不一致
2019-03-05
2021-04-05阅读小笔记:局部性原理
2019-03-05
go语言简单介绍,增强了解
2019-03-05
架构师入门:搭建基本的Eureka架构(从项目里抽取)
2019-03-05
MongoDB 快速扫盲贴
2019-03-05
one + two = 3
2019-03-05
sctf_2019_easy_heap
2019-03-06
PyQt5之音乐播放器
2019-03-06
Redis进阶实践之十八 使用管道模式提高Redis查询的速度
2019-03-06
SQL注入
2019-03-06
MPI Maelstrom POJ - 1502 ⭐⭐ 【Dijkstra裸题】
2019-03-06
Problem 330A - Cakeminator (思维)
2019-03-06
LeetCode75 颜色分类 (三路快排C++实现与应用)
2019-03-06