springboot RedisTemplate+lua接口限流 超过限流次数后返回null问题

lua脚本内容:


local c = redis.call('get',KEYS[1]) or '0' 
if tonumber(c) > tonumber(ARGV[1]) then 
return c end
c = redis.call('incr',KEYS[1])
if tonumber(c) == 1 then 
redis.call('expire',KEYS[1],ARGV[2]) end
return c

接口限流方法:


/**
	 * 接口限流
	 *
	 * @param lockKey 锁key
	 * @param count   限制访问次数
	 * @param period  多少时间内,单位秒
	 */
public static Long limit(String lockKey, int count, int period) {
		// 执行lua脚本
		Object result = staticRedisTemplate.execute(
				new RedisScript<Long>() {
					@Override
					public String getSha1() {
						return SCRIPT_LIMIT_SHA1;
					}

					@Override
					public Class<Long> getResultType() {
						return Long.class;
					}

					@Override
					public String getScriptAsString() {
						return API_LIMIT;
					}

				}, Collections.singletonList(lockKey), count, period);
		return Long.valueOf(StrUtil.utf8Str(result));
	}
	

自定义限流注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Limit {

	// 资源名称,用于描述接口功能
	String name() default "";

	// 资源 key
	String key() default "";

	// key prefix
	String prefix() default "";

	// 时间的,单位秒
	int period();

	// 限制访问次数
	int count();

	// 限制类型
	LimitType limitType() default LimitType.CUSTOMER;
}

切面:

@Around("pointcut(limit)")
	public Object around(ProceedingJoinPoint joinPoint, Limit limit) throws Throwable {
		HttpServletRequest request = ContextUtil.getRequest();
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method signatureMethod = signature.getMethod();
		LimitType limitType = limit.limitType();
		String key = limit.key();
		if (StrUtil.isBlank(key)) {
			if (limitType == LimitType.IP) {
				key = IPUtil.getIp(request);
			} else {
				key = signatureMethod.getName();
			}
		}
		// 拼接key
		String lockKey = StrUtil.join(limit.prefix(), "_", key, "_", request.getRequestURI().replaceAll("/", "_"));
		// redis操作
		Number count = RedisLockUtil.limit(lockKey, limit.count(), limit.period());
		if (null != count && count.intValue() <= limit.count()) {
			log.info("第{}次访问key为 {},描述为 [{}] 的接口", count.intValue(), lockKey, limit.name());
			return joinPoint.proceed();
		} else {
			throw new BizException("访问次数受限制");
		}
	}

接口:

在这里插入图片描述

错误信息:

springboot RedisTemplate+lua接口限流 超过限流次数后返回null问题_第1张图片
springboot RedisTemplate+lua接口限流 超过限流次数后返回null问题_第2张图片
本该是返回6,却变成null了,奇了个怪了

解决方法:

修改lua脚本代码,返回值转换一下类型


local c = redis.call('get',KEYS[1]) or '0' 
if tonumber(c) > tonumber(ARGV[1]) then 
return tonumber(c) end
c = redis.call('incr',KEYS[1])
if tonumber(c) == 1 then 
redis.call('expire',KEYS[1],ARGV[2]) end
return tonumber(c)

重新测试:
springboot RedisTemplate+lua接口限流 超过限流次数后返回null问题_第3张图片
springboot RedisTemplate+lua接口限流 超过限流次数后返回null问题_第4张图片
就此问题解决!!!

你可能感兴趣的:(redis,java,lua,redis,spring,boot)