欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

根据IP限制指定时间内访问接口的次数

程序员文章站 2022-07-05 11:00:06
...

在网上看见有人问一个问题:想限制一下某个接口在一分钟之内只能被同一个ip请求指定次数。

方法比较多,这里就用Redis做一个简单的限制。

大致逻辑:

把请求的ip作为key,请求次数作为value存储在Redis里面,第一次请求value为1,以后每次请求加1,设置过期时间60s,

每次请求都重置过期时间,每次请求过来都需要判断value是否大于指定次数即可;
 

springBoot + Redis实现,springMVC也是同理,主要是思路了;

1. pom文件添加依赖

     <!-- Radis -->
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-data-redis</artifactId>
	</dependency> 

2. 配置文件配置Redis

#redis的ip地址  
redis.hostName=127.0.0.1
#端口号  
redis.port=6379
#如果有密码  
#redis.password=
#客户端超时时间单位是毫秒 默认是2000 
redis.timeout=10000 

3.实现代码

package com.example.servletDemo.controller;

import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/Demo")
public class DemoController {

	@Autowired
	StringRedisTemplate stringRedisTemplate;
	
	/**
	 * key过期时间(秒)
	 */
	private final Long EXPIRATIONTIME_SECONDS = 60L;
	
	/**
	 * key 前缀,防止和其他地方的key可以冲突
	 */
	private final String prefix = "Demo:";

	/**
	 * 请求次数限制:一分钟内一个IP只能请求指定次数
	 * 1.检查IP是否存在(一分钟内是否登录过),如果不存在,设置key和value 过期时间1分钟,
	 * 存在,value+1并且设置过期时间,value大于指定次数,返回请求超过限制
	 * 
	 * key为ip ,value 为调用次数
	 * 
	 * @param request
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/getInfo")
	public String login(HttpServletRequest request) {
		
		// 获取请求IP
		String ip = request.getHeader("x-forwarded-for");
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "null".equals(ip)){
			ip = "" + request.getHeader("Proxy-Client-IP");
		}
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "null".equals(ip)){
			ip = "" + request.getHeader("WL-Proxy-Client-IP");
		}
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "null".equals(ip)){
			ip = "" + request.getRemoteAddr();
		}
		
		// 前缀+ip构成key
		String key = prefix+ip;
		
		//检查key是否存在,返回boolean值
		boolean flag = stringRedisTemplate.hasKey(key);  
		if (flag) {
			// 调用次数+1
			stringRedisTemplate.boundValueOps(key).increment(1);
			// 设置过期时间
			stringRedisTemplate.expire(ip, EXPIRATIONTIME_SECONDS,TimeUnit.SECONDS);
			
			String sumVal = stringRedisTemplate.opsForValue().get(key);
			int sum = Integer.valueOf(sumVal);
			if (sum > 3) {

				System.out.println("第" + sum + "次请求,请求失败!");
				return "一分钟内不能再次请求!";
			}
		}else {
			// 第一次调用,所以value(调用次数)设置为1
			stringRedisTemplate.opsForValue().set(key, "1",EXPIRATIONTIME_SECONDS,TimeUnit.SECONDS);
		}

		String num = stringRedisTemplate.opsForValue().get(key);
		System.out.println("第"+num+"次请求,请求成功!");
		return "请求成功";
	}

}

效果:

根据IP限制指定时间内访问接口的次数