API接口防刷
作者:互联网
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();
}
限制访问拦截器
**
* 防刷拦截器
*/
@Component
public 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;
@Configuration
public 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;
@RestController
public 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;
@Component
public 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;
}
}
标签:code,防刷,String,接口,API,key,msg,import,public 来源: https://blog.csdn.net/l_learning/article/details/115766234