##lua脚本,获取参数的失败
我想进行AOP + Redis + lua脚本 进行接口防刷
但是出现了个问题,无法传入参数
每次都有这个问题
以下是我的代码
package com.qiwenshare.file.aop;
import com.qiwenshare.file.annotation.RateLimit;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
@Aspect
@Component
public class RateLimitAspect {
@Autowired
private RedisTemplate redisTemplate;
private static final DefaultRedisScript<Long> redisScript;
static{
redisScript = new DefaultRedisScript<>();
redisScript.setLocation(new ClassPathResource("RateLimit.lua"));
redisScript.setResultType(Long.class);
}
@Around("@annotation(rateLimit)")
public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String key = request.getRequestURI() + ":" + request.getMethod() + ":" + request.getRemoteAddr();
// 构造Redis中存储的键名
String redisKey = "rate_limit:" + key;
Long limit = rateLimit.limit();
Long timeout = rateLimit.timeout();
// 执行Lua脚本
Long result = (Long)redisTemplate.execute(redisScript, Collections.singletonList(redisKey), limit.toString(), timeout.toString());
if (result != null && result == 1) {
// 请求次数未超限,继续执行方法
return joinPoint.proceed();
} else {
// 请求次数超限,返回限流提示或异常
throw new RuntimeException("接口请求过于频繁,请稍后再试!");
}
}
}
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by fuzhongsuo.
--- DateTime: 2024/8/14 15:04
---
local current = tonumber(redis.call('get', KEYS[1]))
local limit = tonumber(ARGV[1])
local timeout = tonumber(ARGV[2])
redis.call('set', 'debug:limit', limit)
redis.call('set', 'debug:expireSeconds', timeout)
if current == nil then
current = 0
redis.call('set',KEYS[1],current)
redis.call('expire', KEYS[1], ARGV[2])
end
if current + 1 > limit then
return 0
else redis.call('INCRBY', KEYS[1], 1)
return 1
end
为了排查问题,先修改一下lua脚本,把我需要传的参数 limt
timeout
存入redis进行查看,排查到底是什么原因
redis.call('set','test1',limit)
redis.call('set','test1',time)
结果发现,存入redis的是以对象序列化的
其实问题就出在
private RedisTemplate<String,String> redisTemplate;
没有配置
RedisTemplate<String, String> 中,泛型参数指定了模板操作的键(keys)和值(values)的数据类型。第一个泛型参数 String 指定了键(Key)的类型。在这个例子中,键是 String 类型的,这意味着所有的键都将以字符串形式存储在Redis中。
第二个泛型参数 String 指定了值(Value)的类型。在这个例子中,值也是 String 类型的,这意味着所有的值都将以字符串形式存储在Redis中。
这样就完美解决了这个问题,但是花费了我 4个小时,才明白问题