API接口防刷
发布日期: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秒